Sign inSign up

georgegozal/duckdns-updater

By georgegozal

Updated 16 days ago

Keeps a DuckDNS record on your current IP — and reports unhealthy when it stops

Image
Networking
0

436

georgegozal/duckdns-updater repository overview

Keeps a DuckDNS hostname pointed at your current public IP. One small container, no dependencies, and — the reason it exists — it reports unhealthy when it stops working.

linux/amd64 + linux/arm64 · ~12MB compressed · runs as uid 10001, no privileges

docker run -d --name duckdns --restart unless-stopped \
  -e DUCKDNS_DOMAINS=myhost \
  -e DUCKDNS_TOKEN=your-token \
  georgegozal/duckdns-updater:1

DUCKDNS_DOMAINS is comma-separated and takes the subdomain only, without .duckdns.org: myhost,another,third.

Why not three lines in a compose file

The usual inline version is a while loop around curl, and it mostly works. What it cannot do is fail:

entrypoint: [sh, -c, 'while :; do curl -fsS "https://www.duckdns.org/update?..."; sleep 300; done']

DuckDNS answers HTTP 200 for both success and failure, distinguishing them only by a response body of OK or KO. So curl --fail succeeds on a rejected update, the loop prints KO, sleeps, and the container stays contentedly running — forever.

That matters because of what depends on this record. On a residential connection it is how Let's Encrypt finds your host at renewal time, roughly every 60 days. A stale record means the challenge reaches the wrong address and renewal fails — and with an inline loop you find out when the certificate expires, months after the cause.

This image checks the response body, records the last successful update, and fails its healthcheck when that becomes too old. docker ps shows the problem while there is still time to fix it.

Configuration

VariableDefault
DUCKDNS_DOMAINSrequiredComma-separated subdomains, no .duckdns.org
DUCKDNS_TOKENrequiredYour DuckDNS token
DUCKDNS_TOKEN_FILE—Read the token from a file instead — a Docker secret, or a tightly-permissioned mount
INTERVAL300Seconds between updates
RETRIES3Attempts per round, on network failure only
DUCKDNS_IPV6—An AAAA address to set alongside the A record
STATE_DIR/var/lib/duckdnsWhere the last-success timestamp lives
TZUTCTimezone for log timestamps

Whitespace is stripped from the token. A trailing newline — which a token pasted into an .env file or a secret usually keeps — otherwise produces a bare KO with no hint about why.

The public IP is never looked up. ip= is sent empty, so DuckDNS uses the source address it sees. That is both correct behind NAT and means no third-party "what is my IP" service is involved.

The token is never written to the logs.

Health

HEALTHCHECK  interval=60s  timeout=10s  start-period=30s  retries=2

Unhealthy once the last success is older than INTERVAL * 3 — enough tolerance that one failed round does not flap the status, soon enough that a persistent failure surfaces long before a certificate renewal comes due.

docker inspect --format '{{.State.Health.Status}}' duckdns

A KO is treated as a configuration error and is not retried: retrying cannot fix a wrong token, and hammering DuckDNS about it is rude. Network failures are retried with a short backoff instead of waiting a whole interval.

compose

services:
  duckdns:
    image: georgegozal/duckdns-updater:1
    container_name: duckdns
    restart: unless-stopped
    environment:
      DUCKDNS_DOMAINS: ${DUCKDNS_DOMAINS:?}
      DUCKDNS_TOKEN: ${DUCKDNS_TOKEN:?}
    volumes:
      # Keeps the last-success timestamp across restarts, so a restart does not
      # reset the health window and hide a problem that was already showing.
      - duckdns_state:/var/lib/duckdns
    logging:
      driver: json-file
      options: { max-size: "10m", max-file: "3" }

volumes:
  duckdns_state:

Tags

1Use this one. Latest 1.x — patches automatically, never a breaking change
1.0.0Exact version, never moves
latestLatest overall, including future major versions

Tag summary

Content type

Image

Digest

sha256:95d077d8e

Size

5.9 MB

Last updated

16 days ago

docker pull georgegozal/duckdns-updater