💡 System Architecture Note: This repository contains the Worker Node. It requires a running WebGuard Core instance to receive monitoring jobs and report results.
WebGuard Instance is a worker service for executing monitoring jobs from WebGuard Core and reporting the results back to the core API.
The current package boundaries and dependency rule are documented in Architecture.
- Core-Compatible API Contract
- Core instance contract at
GET /api/instances/monitorings POST /api/instances/monitoring-responsesPOST /api/instances/ssl-resultsPOST /api/instances/domain-results- additive raw observations for derived health; see the monitoring observation contract
- Feature-flagged lease protocol: claim, complete, and release monitoring jobs
X-INSTANCE-CODE+X-API-KEYheader authentication
- Core instance contract at
- Parallel Monitoring Execution
- Response, SSL, and domain expiration phases run in parallel
- Worker-based parallel processing for monitoring jobs
- Simple Operations
- Docker-first local and production setup
- Liveness:
GET /livez; readiness:GET /readyz; Prometheus metrics:GET /metrics
- Predictable Scheduling
- Infrastructure checks keep the five-minute dispatcher cadence
- HTTP and keyword website checks run at least 15 minutes apart per monitoring and location
- Docker
- Docker Compose
- A running WebGuard Core instance
-
Clone the repository
git clone git@github.com:marcel-breuer/webguard-instance.git cd webguard-instance -
Configure environment
cp .env.example .env
Required values:
WEBGUARD_LOCATIONWEBGUARD_CORE_API_KEYWEBGUARD_CORE_API_URL
-
Start services Local development:
./start-dev.sh
Production-style:
docker compose -f compose.yml up -d --build
-
Verify health
curl http://localhost:8080/
- Run one-off monitoring:
docker compose -f compose.yml run --rm webguard-instance monitoring
- Stop production compose:
docker compose -f compose.yml down
- Stop local development compose:
docker compose -f compose.yml -f docker-compose.override.yml down
Main integration settings:
WEBGUARD_LOCATION(instance code used forlocationquery andX-INSTANCE-CODEheader)WEBGUARD_CORE_API_KEYWEBGUARD_CORE_API_URLWEBGUARD_INSTANCE_API_BASE_PATH(default:/api/instances; only this Core instance route family is accepted)
Runtime settings:
QUEUE_DEFAULT_WORKERS(default:3)RUN_MAX_CONCURRENCY(default:QUEUE_DEFAULT_WORKERS; shared upper bound across all check phases)WEBGUARD_JOB_LEASES_ENABLED(default:false; use Core-issued leases instead of legacy polling)WEBGUARD_JOB_LEASES_DUAL_WRITE(default:false; also post legacy result endpoints during a staged Core rollout)WEBGUARD_INSTANCE_ID(required when leases are enabled; stable worker identity, distinct from its location)WEBGUARD_JOB_LEASE_MAX_BATCH(default:QUEUE_DEFAULT_WORKERS; maximum jobs requested in one lease claim)WEBGUARD_ALLOW_PRIVATE_TARGETS(default:false; set totrueonly when this worker should monitor private, loopback, or link-local targets)SHUTDOWN_DRAIN_TIMEOUT_SECONDS(default:10; drain deadline afterSIGTERM)PORT(default:8080)
See .env.example for full defaults.
Production deployment and rollback guidance is documented in the production instance runbook.
Core supplies check_interval_seconds with each monitoring. The worker honors
that per-monitoring minimum start-to-start interval for regular response checks
and reports the executed value with the result. HTTP and keyword checks currently
use 900 seconds; other active checks retain the documented Core cadence. A
delayed worker run may execute later, never sooner.
The contract and rollout sequence for horizontally scaled workers are in the monitoring job lease protocol.
The supported Core scanner contract uses the /api/instances route family,
published by WebGuard Core as the
WebGuard Instance API contract.
The adapter accepts only this instance path; it never calls browser routes.
Each executed monitoring job carries one UUID v4 callback identifier. The
worker sends it as the Idempotency-Key header on monitoring, SSL, and domain
result callbacks and reuses it for bounded transport/5xx retries. The key is
never included in the JSON payload and contains no target or credential data.
For leased jobs, a valid Core-issued execution key is reused; older or missing lease keys are replaced with a worker-generated UUID v4. Independent executions receive different keys. Core can therefore replay an ambiguous callback safely without storing a duplicate observation or repeating its side effects. Older Core versions ignore the additive header and remain compatible.
GET /livezonly confirms that the process can serve HTTP. Docker uses this route for its health check.GET /readyzreturns200only when Core configuration is complete and the instance is not draining. It returns503during configuration errors and graceful shutdown.GET /metricsexposes Prometheus text metrics for run duration and outcome, active/queued leased jobs, bounded executor outcomes, Core request latency and errors, and lease lifecycle events. It never labels metrics with targets, credentials, monitoring IDs, or job IDs.
On SIGTERM the instance stops scheduling new work, waits up to
SHUTDOWN_DRAIN_TIMEOUT_SECONDS for active work to complete or relinquish its
lease, then shuts down the HTTP server. Telemetry is process-local and can be
scraped without an external backend; OpenTelemetry remains optional and is not
enabled by default.
.github/workflows/ci.yml- formatting, vet, tests, binary build, container build check
.github/workflows/docker-image.yml- multi-arch image build and publish to GHCR on
mainandv*tags - release notes generation and
CHANGELOG.mdupdates forv*tags
- multi-arch image build and publish to GHCR on