# onlyscans REMOTE AGENT install kit (Phase 2) — run this ON THE REMOTE SITE's # docker host, NOT on the central box. One agent = one location = one vantage. # # Prereqs (do these FIRST, on the central instance's web UI): # 1. Admin → /agents → create the LOCATION for this site (e.g. "chch-office"). # 2. /agents → New agent: username (e.g. "chch-1") + that location. The # password is shown ONCE — put it in .env as AGENT_PASSWORD below. # # Then on this host: # cp .env.agent.example .env (fill AGENT_IDENTITY / AGENT_PASSWORD) # → docker compose -f docker-compose.agent.yml up -d # The worker image pulls anonymously from the public registry — no # `docker login` needed. (Fallback if the registry is ever re-privatized: # Sam will send login instructions with the kit credentials.) # Full walkthrough: README.md in this repo. # (Running a SECOND agent on the same box: each agent needs its OWN # credentials — copy this file to e.g. docker-compose.agent2.yml AND create # a second env file (.env-agent2), then run it with # `docker compose --env-file .env-agent2 -f docker-compose.agent2.yml up -d`. # In the copy, change the project `name:` and `container_name` below — # otherwise compose project + container collide with the first agent. Two # agents sharing one .env would share one auth record — unsupported and # silently wrong.) # # The agent talks to the central PocketBase over the public tunnel TLS # (https://scan-api.noctools.nz) — credentials and results are encrypted in # transit. It needs egress to: scan-api.noctools.nz:443, the scan targets, # and (only if CVE_MATCH_API is set) that API host. name: onlyscans-agent services: agent: image: gitea.noctools.nz/noctools/onlyscans-worker:20260821-3 # Bump the tag to track the central worker version (see README.md). container_name: onlyscans-agent restart: unless-stopped cap_add: - NET_RAW # nmap/masscan raw-packet scanning - NET_ADMIN environment: PB_URL: https://scan-api.noctools.nz AGENT_IDENTITY: ${AGENT_IDENTITY:?set in .env — the username created on /agents} AGENT_PASSWORD: ${AGENT_PASSWORD:?set in .env — the shown-once password} AGENT_HEARTBEAT_SECONDS: 30 # Shown on /agents (agent_version) — bump together with the image tag # when upgrading so the central UI can confirm the rollout. AGENT_VERSION: 20260821-3 # Optional: CVE matching via the central cve-match API. Leave EMPTY unless # Sam has given you a CVE_MATCH_API URL + token (its public exposure is a # manual central-side step). Without it, scans still complete — the CVE # stage is skipped for agents with no local NVD DB. CVE_MATCH_API: ${CVE_MATCH_API:-} CVE_MATCH_TOKEN: ${CVE_MATCH_TOKEN:-} POLL_INTERVAL_MS: 5000 NMAP_VERSION_INTENSITY: 9 FINGERPRINT_CONCURRENCY: 4 healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:8081/healthz"] interval: 15s timeout: 5s retries: 4 deploy: resources: limits: memory: 512m # ── Host-network variant ──────────────────────────────────────────────────── # The default bridge network can only scan what it routes to. To scan the # site's LAN directly (ARP-level discovery, non-routed subnets), swap the # service to host networking. Each agent on a shared host stack needs its OWN # health port — and the healthcheck `test` below MUST be bumped in tandem # (it hardcodes the port; a stale probe would hit the FIRST agent's healthz # and report false-healthy for the others): # # services: # agent: # image: gitea.noctools.nz/noctools/onlyscans-worker:20260821-3 # network_mode: host # container shares the host's stack # environment: # ... # WORKER_HEALTH_PORT: "8082" # 8083, 8084… for further agents on this box # healthcheck: # test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:8082/healthz"] # # …keep matching WORKER_HEALTH_PORT on every copy # # NO ports:, NO networks: — host mode ignores them # # Masscan at high rates can disrupt fragile networks; coordinate rate with # the profile's masscan_rate on the central instance.