Repository navigation
Docktornet 1.1.0 kept Nginx Proxy Manager, Cloudflare DNS and Gatus in step with your containers' labels. This release adds Caddy as a second reverse proxy, chosen per service with docktornet.caddy.* labels, beside NPM or in its place. Every proxy host, Caddy route and DNS record the server manages now carries a marker naming its service, so a server that loses its database takes back what it owns instead of forgetting it.
The server also gains three subcommands, audit, backup and healthcheck, and removes what a departed service left behind within a minute of its grace period ending, where it used to wait for the hourly resync.
Docktornet publishes no images. Build both from the tag:
git checkout v1.2.0
docker build -f crates/server/Dockerfile -t docktornet-server:1.2.0 .
docker build -f crates/agent/Dockerfile -t docktornet-agent:1.2.0 .Important
This release migrates the database, and refuses settings 1.1.0 accepted. A 1.1.0 server cannot open the database 1.2.0 leaves, so copy docktornet.db before the first start. The server and the agents now read server.env and agent.env in place of one .env, and refuse a DOCKTORNET_SECRET under 32 characters. Read Upgrade before you start.
What's new
Caddy beside NPM
docktornet.caddy.<index>.host,.portand.schemeroute a service through Caddy. The server writes each route through Caddy's admin API inside one anchor route of your config, set withDOCKTORNET_CADDY_ADMIN_URLandDOCKTORNET_CADDY_ANCHOR_ID. A host one service already routes is refused to another. Without the admin URL, Caddy labels are skipped with a warning. #20- A Caddy route has the same lifecycle as an NPM proxy host. It keeps serving through the grace period after its service leaves, comes back if the service returns, and is deleted once the grace period ends. Caddy has its own circuit breaker. #21
- A route deleted or edited by hand, or wiped by
caddy reload, is back within a minute. The server restores what it stored, never what the labels say now. #22 - Authenticated
/healthzand the audit cover Caddy./healthzreports the Caddy breaker and whether the anchor was found, and readsdegradedwhen either is wrong. #23 - The deployment guide has the whole setup: a bootstrap config, how to keep the admin API off other networks, a Cloudflare tunnel in front, and how to move a service from NPM to Caddy. #24
Knowing what Docktornet owns
- Every managed resource names its owner. An NPM proxy host carries
meta.docktornet, a Cloudflare record the commentdocktornet:<service_id>, and a Caddy route its@id. A server that lost its database takes back its own resources by marker, with no adoption flag. Adoption by hostname takes only unmarked resources, and a resource marked for another service is refused. #5 docktornet-server auditprints what does not line up, as one JSON report: resources marked but not recorded, pending removals, recorded resources that are missing or unmarked, and unmarked NPM hosts whose upstream does not answer. It changes nothing, so it runs next to the live server withdocker exec, and exits 1 when it finds something.audit --only caddyreaches Caddy alone. #8 #23
Running the server
docktornet-server backupcopies the database while the server runs, andscripts/backup_external_state.shnow saves the database and the Gatus config beside NPM and Cloudflare, finishes a backup whole or not at all, and keeps the newest 14. #13docktornet-server healthcheckgives compose something to probe in the distroless image. The compose files use it, and agents wait for a healthy server. #14- Authenticated
/healthzsays more: the server's version and each agent's, the last full resync's result and the NPM breaker's state. The server logs a warning when an agent runs another version. The public response is unchanged. #6 #14 - A database the next recreate would lose stops the server. A relative
DOCKTORNET_DB_PATH, or a database on the container's own filesystem, is refused with the directory to mount a volume at. The image now puts the database in/data. #6 - Secrets stay where they belong. The agent, which mounts the Docker socket, no longer holds the NPM password or the Cloudflare token, a weak or placeholder
DOCKTORNET_SECRETis refused, and no secret appears in debug output. #12
Gatus
docktornet.gatus.<index>.severityand.areaclassify a monitor, anddocktornet-classification.jsonbeside the Gatus files maps each endpoint to its service, host, severity, area and alert thresholds, for an alerting service to read. An unknown value drops the monitor with a warning, so a typo never demotes a critical endpoint. #7
Removals and drift
- A departed service's resources go within a minute of the grace period ending, and Gatus drops the deleted monitor, which it never noticed before. #4
- The grace period runs on the server's clock, so an agent with a wrong clock can no longer have a resource deleted early. #9
- Removing a
docktornet.npm.<index>group deletes its proxy host at once, and a group with a typo keeps its host, as a Caddy group does. #18 #25 - A container whose labels are all invalid loses its resources once the grace period ends. Each push used to start the grace period again. #26
- The full resync puts back every field Docktornet sets on an NPM proxy host, not only the certificate, and no longer rewrites hosts that have not drifted. An edit made in NPM's interface to a managed host is set back within the hour. #10
Smaller things
- An NPM update keeps the keys NPM stores in a host's
meta, where it used to wipe them. #5 - Another agent pushing the same machine id from another address is refused with
409, and an invalidDOCKTORNET_MACHINE_IDstops the agent. #11 - A slow NPM or Cloudflare no longer queues one apply per poll: each machine has one apply running and one waiting. #11
- The full resync leaves NPM alone while its breaker is open, and failed Gatus writes leave no temp files. #9
- Both images pin their base images by digest, build with
--locked, and build under Podman. #15 DOCKTORNET_CF_API_URLpoints the server at another Cloudflare API address, such as a test stub. #17- The TLS library both binaries connect with, and the certificates it trusts, are past six published flaws.
Upgrade
- Copy
docktornet.dbsomewhere safe. Migrations 0006 to 0010 run at the first start. - Split
.envintoserver.envandagent.env, next to the compose file each host runs, usingserver.env.exampleandagent.env.exampleas the lists of keys. - If
DOCKTORNET_SECRETis shorter than 32 characters or containschangeme, generate a new one withopenssl rand -hex 32and put it inserver.envand everyagent.env. - Set
SERVER_IMAGEandAGENT_IMAGEto the 1.2.0 images you built. The compose files no longer start without them. - Make sure the server's database is on a volume at
/data, and leaveDOCKTORNET_DB_PATHunset. - Recreate the server and every agent together:
docker compose up -dThe first full resync, at startup, writes a marker on every proxy host and DNS record the server manages, so NPM reloads nginx once per proxy host on that pass. The deployment guide walks through the .env split.
The full list, line by line, is in the changelog.