Sign inSign up

3nderium/labddns

By 3nderium

•Updated about 10 hours ago

Small Cloudflare DDNS updater with a status page. Python standard library only, runs non-root.

Image
Networking
0

13

3nderium/labddns repository overview

⁠labddns

A small Cloudflare dynamic DNS updater with a one page status UI. It keeps one or more A records pointed at the public IPv4 address your network appears from.

It is built for networks where the gateway cannot tell its own public address, for example a router sitting in a DMZ behind an ISP modem. Rather than reading a WAN interface, it asks the outside world which address it is seen from.

⁠What it does

  • Every 5 minutes (configurable) it reads the public IP from Cloudflare's /cdn-cgi/trace, falling back to api4.ipify.org.
  • For each name in DDNS_DOMAINS it creates or updates the A record through the Cloudflare API when the address differs.
  • Records are DNS only (grey cloud, not proxied) and IPv4 only, so they suit VPN endpoints such as WireGuard.
  • Records it manages carry the comment managed by cntr-ddns-01.
  • A status page shows the current and previous IP, the result per record, the change history and a "check now" button.
  • State is kept in /config/state.json, so history survives a redeploy.

⁠Image

  • Base python:3.12-slim, Python standard library only, no pip packages.
  • Runs as a non-root user. Works with a read-only root filesystem, all capabilities dropped and no-new-privileges.
  • Listens on port 7591. Health check on /healthz.
  • No secrets in the image. Everything comes from the environment.

⁠Quick start

services:
  ddns:
    image: 3nderium/labddns:latest
    restart: unless-stopped
    read_only: true
    tmpfs:
      - /tmp
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    environment:
      CLOUDFLARE_API_TOKEN: ${CLOUDFLARE_API_TOKEN}
      DDNS_DOMAINS: vpn.example.com,home.example.com
      DDNS_USER: ${DDNS_USER}
      DDNS_PASSWORD: ${DDNS_PASSWORD}
    ports:
      - "7591:7591"
    volumes:
      - ddns-config:/config

volumes:
  ddns-config:

Then open http://<host>:7591.

The Cloudflare API token needs Zone > DNS > Edit on the zone that holds the names.

⁠Environment

VariableDefaultPurpose
CLOUDFLARE_API_TOKENnone, requiredAPI token with Zone > DNS > Edit on the zone
DDNS_DOMAINSnone useful, set itComma separated names to keep updated
DDNS_INTERVAL_SECONDS300Seconds between checks, minimum 60
DDNS_TTL60TTL for records it creates or updates
DDNS_USER, DDNS_PASSWORDunsetLogin for the web UI. With both unset the UI is open
DDNS_SECRETgeneratedCookie signing secret. Generated into /config when unset
TRUSTED_PROXYunsetIP of your reverse proxy. Only its X-Forwarded-For is believed
LAB_DOMAINunsetYour domain. Used with DDNS_HTTPS_ONLY
DDNS_HTTPS_ONLYfalsetrue sends any request not from TRUSTED_PROXY to https://ddns.<LAB_DOMAIN> and marks the cookie Secure
DDNS_STATUS_CLIENTSunsetComma separated IPs allowed to GET /api/state without a login, for a dashboard
PORT7591Listen port
TZUTCTime zone for log lines

Always set DDNS_DOMAINS to your own names.

⁠Endpoints

PathPurpose
/Status page
/healthzHealth check, no login
/api/stateCurrent state as JSON
/api/checkPOST to run a check now

⁠Volume

/config holds state.json (IP history and per record results) and the generated cookie secret.

⁠Tags

latest only. Built by hand for a home lab, so there is no release schedule and no support. Use it as is or as a starting point for your own.

Tag summary

Content type

Image

Digest

sha256:a905a7f30…

Size

41.3 MB

Last updated

about 10 hours ago

docker pull 3nderium/labddns