Cloudflare DDNS
Holden can automatically create and update Cloudflare DNS records for your apps. When a container with a domain: starts, its domain gets pointed to your server’s public IP — no manual DNS management needed.
This is handled by a lightweight sidecar container (holden-ddns) that watches Docker labels and syncs them to Cloudflare.
How It Works
Section titled “How It Works”- The sidecar reads
holden.domainslabels from all running containers via the Docker socket - It detects your server’s public IP
- For each domain, it finds the matching Cloudflare zone and creates or updates an A record
- It reacts to container start/stop events and periodically checks for IP changes
flowchart LR
D[Docker socket] -->|read labels| S[holden-ddns]
S -->|detect IP| IP[Public IP]
S -->|update records| CF[Cloudflare API]
Set CLOUDFLARE_API_TOKEN on the Holden container. When present, Holden spawns the holden-ddns sidecar automatically. Remove the variable to disable DDNS.
Creating an API Token
Section titled “Creating an API Token”- Go to Cloudflare API Tokens
- Click Create Token
- Use the Edit zone DNS template, or create a custom token with:
- Zone > Zone > Read — to list your zones
- Zone > DNS > Edit — to create and update records
- Set the zone scope to All zones (or limit to specific zones)
Per-Service Proxy Override
Section titled “Per-Service Proxy Override”The holden.domains Label
Section titled “The holden.domains Label”Holden sets a holden.domains label on every container that has a domain: configured:
holden.domains: "app.example.com,www.example.com"This is a comma-separated list of all domains for that service. The DDNS sidecar reads this label — it never parses Traefik rules or reads your holden.yml files.
The Overseer also sets holden.domains on the Holden container itself when HOLDEN_PUBLIC_DOMAIN is configured, so the dashboard/webhook domain gets DNS records too.
Record Management
Section titled “Record Management”The sidecar adds a comment to every DNS record it creates:
managed by holdenUpdate Behavior
Section titled “Update Behavior”| Record exists? | Comment | FORCE off | FORCE on |
|---|---|---|---|
| No | — | Creates record | Creates record |
| Yes, wrong IP | managed by holden | Updates record | Updates record |
| Yes, wrong IP | Other / none | Skips | Updates record |
| Yes, correct IP | — | No-op | No-op |
Without FORCE, the sidecar only touches records it created. This prevents accidentally overwriting records managed by other tools or set manually.
Removed Domains
Section titled “Removed Domains”When a domain is removed from your config (or an app is deleted), the DNS record is not automatically deleted or modified. It continues pointing at your server’s IP, where Traefik will return a 404. Clean up stale records manually in the Cloudflare dashboard when you’re ready.
Event-Driven Updates
Section titled “Event-Driven Updates”The sidecar subscribes to Docker container events (start, stop, die). When a Holden-managed container changes, it re-scans all labels and syncs. This means DNS updates happen within seconds of a deployment.
A periodic fallback (every 5 minutes) catches IP changes that happen without container events — for example, if your ISP assigns a new IP.