# Technitium DDNS Python utility that fetches the host's public IPv4 and IPv6 and updates `A` and `AAAA` records for a given hostname in a zone hosted on a Technitium DNS server. This repository contains a single service that supports two update backends: - **HTTP_API** — use Technitium's HTTP API (token-based) to add/overwrite records. - **RFC2136** — use standard DNS dynamic updates (RFC2136), optionally authenticated with a TSIG key. The service runs in a continuous loop by default and updates every `UPDATE_INTERVAL` seconds (configurable via environment variables). ## Quick start 1. Create `.env` and fill in secrets and other variables. 2. Build and run: ```bash docker compose build docker compose up -d ``` Or to run with Docker directly: ```bash docker build -t technitium-ddns . docker run -d --name technitium-ddns --env-file .env technitium-ddns ``` ## Environment variables You can set these in `.env`, via `docker-compose.yml`, or when running the container. General: - `LOG_LEVEL` - `DEBUG`, `INFO`, `WARNING`, `ERROR` or `FATAL`. - `LOG_FILE` - path of the log file or empty to log to stdout/stderr. - `BACKEND` — `HTTP_API` (default) or `RFC2136`. - `RUN_ONCE` — `1` to run a single update and exit, `0` to loop continuously (default `0`). - `UPDATE_INTERVAL` — seconds between updates when looping (default `300`). - `ZONE` — DNS zone to update the record into. - `RECORD_NAME` — record name (left part) — the script updates `.`. - `TTL` — record TTL in seconds (default `300`). - `SKIP_IPV6` — set to `1` to skip AAAA updates. HTTP API backend (Technitium): - `TDNS_HOST` — Technitium base URL. - `TDNS_API_TOKEN` — API token generated in Technitium web console (**required** for `HTTP_API`). RFC2136 backend: - `RFC2136_SERVER` — authoritative DNS server IP or hostname for dynamic updates (required for `RFC2136`). - `RFC2136_PORT` — port (default `53`). - `RFC2136_TSIG_NAME` — optional TSIG key name. - `RFC2136_TSIG_KEY` — optional TSIG key (base64). - `RFC2136_TSIG_ALGO` — optional TSIG algorithm (default `hmac-sha256.`). ## Example `.env` ```ini # Log level and log file LOG_LEVEL=INFO LOG_FILE=/var/log/technitium-ddns.log # Choose HTTP_API or RFC2136 BACKEND=HTTP_API # If RUN_ONCE=1 the container runs once and exits (good for host cron). RUN_ONCE=0 UPDATE_INTERVAL=300 ZONE=example.com RECORD_NAME=ddns TTL=300 SKIP_IPV6=0 # HTTP API (Technitium) TDNS_HOST=http://technitium:5380 TDNS_API_TOKEN=YOUR_TECHNITIUM_TOKEN_HERE # RFC2136 (if using RFC2136 backend) RFC2136_SERVER=192.0.2.5 RFC2136_PORT=53 # Optional TSIG: RFC2136_TSIG_NAME=ddns-key RFC2136_TSIG_KEY=base64encodedkey== RFC2136_TSIG_ALGO=hmac-sha256. ``` ## How it behaves - On each run (single-run or loop iteration) the script: 1. Detects public IPv4 (via `api.ipify.org`, fallback to other services). 2. Detects public IPv6 (unless `SKIP_IPV6=1`). 3. Queries current `A` / `AAAA` values; if they already match the current public IP, update is skipped. 4. Otherwise updates the record(s) using the selected backend. - `HTTP_API` backend calls Technitium endpoint `/api/zones/records/add` with `overwrite=true`. - `RFC2136` backend issues a dynamic DNS update packet and can use TSIG for authentication. ## Running as a cron job on the host (recommended for many setups) If you prefer not to run a continuously-looping container, set `RUN_ONCE=1` and run the container from a host cron or systemd timer: Example host systemd timer unit (recommended): ```ini # /etc/systemd/system/tdns-updater-run.service [Unit] Description=Run tdns-updater once [Service] Type=oneshot WorkingDirectory=/path/to/project ExecStart=/usr/bin/docker compose run --rm tdns-updater ``` ```ini # /etc/systemd/system/tdns-updater-run.timer [Unit] Description=Run tdns-updater every 5 minutes [Timer] OnBootSec=1min OnUnitActiveSec=5min [Install] WantedBy=timers.target ``` ## RFC2136 notes - Many servers expect dynamic updates to come from an allowed IP or require TSIG authentication. If using Technitium as the RFC2136 target, check its dynamic update / ACL settings and configure TSIG if required. - The script supports TSIG via `RFC2136_TSIG_NAME` and `RFC2136_TSIG_KEY` (base64). Provide `RFC2136_TSIG_ALGO` like `hmac-sha256.` if needed. ## TLS / self-signed certs If your `TDNS_HOST` is `https://` with a self-signed certificate, mount CA certificate(s) into the container and set `REQUESTS_CA_BUNDLE` or `SSL_CERT_FILE` appropriately, or use valid certificates to avoid modifying the image: Example `docker-compose.yml` snippet for a CA bundle file: ```yaml volumes: - ./my-ca.pem:/usr/local/share/ca-certificates/my-ca.crt:ro ``` (then update CA store inside the image at build time, or pass `REQUESTS_CA_BUNDLE` pointing to the file.) ## Security - Treat `TDNS_API_TOKEN` and `RFC2136_TSIG_KEY` as secrets. Do not commit them to VCS. - For production, use Docker secrets, environment injection from your orchestrator, or mount a read-only file containing secrets.