Skip to content

rsbfox/technitium-ddns

Repository files navigation

technitium-ddns

Not affiliated with or endorsed by Technitium.

Dynamic DNS updater for Technitium DNS Server.

Reads standard BIND 9 zone files and pushes records to Technitium via its HTTP API. Designed for self-hosted DNS on a home server with a dynamic IP. Supports split-horizon DNS so internal clients get LAN addresses and external clients get WAN addresses automatically.

Features

  • BIND 9 zone file format — works with existing zone files
  • Supports A, AAAA, CAA, CNAME, MX, NS, PTR, SOA, SRV, TXT
  • Technitium APP records with $APP directive for any installed app
  • Split Horizon shorthand — true/false generates the right JSON automatically
  • ${WAN} and ${LAN} placeholders substituted at runtime
  • $ORIGIN with relative names (no trailing dot appended to current origin)
  • Multi-line records with ( ), multi-part TXT strings, full escape sequence support
  • serial auto — lets Technitium manage SOA serial with its date scheme
  • --dry-run — prints resolved FQDNs and real IPs, no API calls made
  • Zones auto-created if missing
  • Automatic WAN IP detection and bogon address validation
  • Logs to terminal when interactive, syslog when run from cron/systemd
  • Optional FreeDNS update support

Requirements

Optional

Split Horizon — install from the Technitium app store to use APP true/false records. Returns ${LAN} to private clients and ${WAN} to public clients.

WildIp — install from the Technitium app store. Resolves the IP encoded in the label itself, e.g. 1.2.3.4.wildip.example.com → A 1.2.3.4.

FreeDNS (freedns.afraid.org) — free dynamic DNS. Register subdomains on any of thousands of community-shared domains. They also support pointing an NS record at your own server, making Technitium authoritative for that subdomain — enabling wildcard records, split-horizon DNS, and automated DNS-01 Let's Encrypt challenges. Set FREEDNS_KEYS in the config to push IP updates on each run.

Install

Install dependencies:

sudo apt install grepcidr jq gettext-base

Install:

git clone https://github.com/rsbfox/technitium-ddns
cd technitium-ddns
sudo bash install.sh

Edit the config:

sudo nano /etc/technitium-ddns/technitium-ddns.conf

See what it will do before touching anything:

sudo technitium-ddns --dry-run

Usage

sudo technitium-ddns                                     # all zones
sudo technitium-ddns your.domain                         # one zone
sudo technitium-ddns --dry-run                           # preview all zones
sudo technitium-ddns --dry-run your.domain               # preview one zone
sudo technitium-ddns example.com                         # always dry run, feature demo
sudo technitium-ddns --run-tests                         # run all zones in tests/
sudo technitium-ddns --run-tests stress.test             # run one test zone
sudo technitium-ddns --run-tests --dry-run               # dry run all test zones
sudo technitium-ddns --run-tests --dry-run stress.test   # dry run one test zone

Override IPs without editing config:

sudo WAN=1.2.3.4 LAN=192.168.1.1 technitium-ddns

Zone File Format

Zones live under zones/ inside the config directory, one subdirectory per zone named after the FQDN, each containing a main.zone file:

/etc/technitium-ddns/
    technitium-ddns.conf
    zones/
        example.com/
            main.zone      ← always dry run, feature demo
        your.domain/
            main.zone      ← your zone, must be root:root 640
        0.168.192.in-addr.arpa/
            main.zone      ← reverse zone
    tests/
        stress.test/
            main.zone      ← must use .test TLD (RFC 6761)

Zone files are standard BIND 9 format. Copy and edit example.com/main.zone to get started. Run sudo technitium-ddns example.com to see a full dry run of the example zone demonstrating every supported feature.

$TTL 1h
$APP SplitHorizon.SimpleAddress Split Horizon

@       IN SOA  ns1 hostmaster auto 3600 900 604800 300
@       IN NS   ns1
@       IN MX   10 mail
@       IN TXT  "v=spf1 ip4:${WAN} ~all"
@       IN CAA  0 issue "letsencrypt.org"
@       IN APP  true          ; split horizon — LAN gets ${LAN}, WAN gets ${WAN}

ns1     IN A    ${WAN}
mail    IN A    ${WAN}
home    IN APP  false         ; LAN only

$APP directive

Sets the Technitium app for all following APP records. Multiple $APP directives can appear in one file.

$APP SplitHorizon.SimpleAddress Split Horizon

@    IN APP true              ; {"private":["${LAN}"],"public":["${WAN}"]}
home IN APP false             ; {"private":["${LAN}"]}
vpn  IN APP {"private":["10.0.0.2"],"public":["1.2.3.4"]}  ; custom JSON

$APP WildIp.App Wild IP

wildip IN APP                 ; no recordData

true/false shorthand is only valid for SplitHorizon.SimpleAddress. All other apps accept JSON or empty.

Stress Test Zone

The stress-test zone is located at tests/stress.test/main.zone.
If you encounter a valid BIND 9 record that the parser does not handle correctly, please open a PR to add it to the zone.

Test zones must use the .test TLD (RFC 6761). The .test domain is reserved and never delegated in the public DNS, so records pushed to Technitium via --run-tests cannot leak to the internet.

Configuration

/etc/technitium-ddns/technitium-ddns.conf must be root:root 640.

Variable Required Description
WAN_IFACE if needed Network interface for WAN IP detection
LAN_IFACE if needed Network interface for LAN IP detection
TECH_TOKEN yes* Technitium API token (*not needed for --dry-run)
TECH_API_BASE no API base URL (default: http://localhost:5380/api)
FREEDNS_KEYS no Comma-separated afraid.org update keys

WAN_IFACE and LAN_IFACE are only required if your zone files use ${WAN}, ${LAN}, or SplitHorizon.SimpleAddress APP records. Zones with only static records need neither.

Status

Tested on Ubuntu 24.04 with Technitium DNS Server. Use at your own risk.

wan-routable

A networkd-dispatcher script that triggers technitium-ddns automatically when the WAN interface obtains a new routable IP. Validates the IP is public, cycles the interface if a bogon is assigned (e.g. during cable modem sync), and skips the update if the IP hasn't changed.

Requires systemd-networkd as the network renderer (set renderer: networkd in Netplan).

Install:

sudo cp wan-routable /etc/networkd-dispatcher/routable.d/wan-routable
sudo chown root:root /etc/networkd-dispatcher/routable.d/wan-routable
sudo chmod 755 /etc/networkd-dispatcher/routable.d/wan-routable
sudo systemctl enable --now networkd-dispatcher

Edit WAN_IFACE at the top of wan-routable to match your interface name.

About

Dynamic DNS updater for Technitium DNS Server. Extends BIND 9 zone files with Technitium API records. Designed for self-hosted DNS on a home server

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages