← Back to docs

Dynamic DNS

Dynamic DNS

ToolsAPI provides a Dynamic DNS layer under /api/dyndns for hosts whose public address can change over time.

The normal self-service namespace is:

<name>.dyn.tornevall.net

Nested names can be enabled per Dynamic DNS zone, for example:

router.home.dyn.tornevall.net

Administrators may add special Dynamic DNS namespaces and assign hosts outside the default namespace. A typical internal example is gw.tornevall.net.

Authentication model

There are two separate authentication boundaries:

  1. Updater client -> /api/dyndns: a Dynamic DNS token is required.
  2. Dynamic DNS -> DNS writer: no second HTTP/API token is used inside ToolsAPI.

The Dynamic DNS controller validates the client token and host ownership, then calls the existing DNS services directly. The underlying DNS service handles its own provider credentials, such as TSIG for the local DNS master or configured Cloudflare credentials.

Each Tools user has one Dynamic DNS token. The same token can update every Dynamic DNS host owned by that user.

Tokens can be created or rotated from /dyndns.

Supported token transports:

  • Authorization: Bearer <token>
  • X-DynDNS-Token: <token>
  • HTTP Basic password for DynDNS-compatible clients
  • token=<token> as a compatibility fallback

Bearer headers are recommended for scripts and applications.

Update endpoint

Endpoint: POST /api/dyndns/update

Example:

curl -X POST https://tools.tornevall.net/api/dyndns/update \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"hostname":"home.dyn.tornevall.net","address":"auto"}'

address="auto" uses the source address of the HTTP request.

An explicit address may also be sent:

{
  "hostname": "home.dyn.tornevall.net",
  "ipv4": "192.0.2.25"
}

or:

{
  "hostname": "home.dyn.tornevall.net",
  "ipv6": "2001:db8::25"
}

Multiple owned hosts can be updated in one request:

{
  "hosts": [
    "home.dyn.tornevall.net",
    "vpn.dyn.tornevall.net"
  ],
  "address": "auto"
}

Replacement semantics - stale records are removed

Dynamic DNS address updates are treated as desired state, not as ordinary DNS ADD operations.

For every A or AAAA RRset touched by an update, ToolsAPI:

  1. Reads the currently published address records.
  2. Explicitly deletes every existing value for that hostname and record type.
  3. Adds the one requested address, if that family is enabled.
  4. Reads the DNS data again and verifies that the resulting RRset contains exactly the requested address.

This prevents old addresses from remaining beside the new one and causing round-robin or double resolving.

The existing DNS safety rule is retained: ordinary DNS API calls are not given a generic empty-target RRset delete. Dynamic DNS removes the discovered address values explicitly and only manages A/AAAA records belonging to the Dynamic DNS host.

If a host is configured as IPv4-only, stale AAAA records are cleared. The inverse applies to IPv6-only hosts.

Host state

Endpoint: GET /api/dyndns/state?hostname=<hostname>

Authentication is required and the hostname must belong to the token owner.

Example response:

{
  "ok": true,
  "hostname": "gw.tornevall.net",
  "ipv4": "192.0.2.25",
  "ipv6": null,
  "dns_status": "ok",
  "last_dns_sync_at": "2026-08-12T11:00:00+02:00"
}

This endpoint is also suitable for separate internal systems that need the last accepted Dynamic DNS address. For example, a firewall refresh script can read gw.tornevall.net from this endpoint and update its own firewall database. The firewall system remains separate from Dynamic DNS.

List hosts

Endpoint: GET /api/dyndns/hosts

Returns all Dynamic DNS hosts owned by the token user.

Current client address

Endpoint: GET /api/dyndns/ip

Returns the address seen by ToolsAPI. A Dynamic DNS token is required.

DynDNS-compatible endpoint

For routers and devices with traditional Dynamic DNS support:

GET /api/dyndns/nic/update?hostname=home.dyn.tornevall.net&myip=192.0.2.25

If myip is omitted, ToolsAPI uses the source address of the request.

The Dynamic DNS token can be used as the HTTP Basic password.

Typical responses include:

good 192.0.2.25
nochg 192.0.2.25
nohost
badauth
dnserr

nochg means the address stored by ToolsAPI did not change. The DNS RRset may still be rewritten and verified in order to guarantee that stale address records have not survived.

Web interface

User management is available at:

/dyndns

Users can:

  • create hosts in self-service zones
  • enable IPv4 and/or IPv6 management
  • set TTL
  • update a host from the current browser address
  • create or rotate the account Dynamic DNS token
  • see recent update history and DNS status

Administration is available at:

/admin/dyndns

Administrators can:

  • create additional Dynamic DNS namespaces
  • make zones self-service or admin-managed
  • allow or deny nested subdomains
  • configure IPv4/IPv6 availability and default TTL
  • create special hosts for a specific user
  • inspect all configured Dynamic DNS hosts

Linux updater

A ready-to-use client is stored in:

scripts/dyndns/tools-dyndns.sh

Environment variables:

export DYNDNS_HOST="home.dyn.tornevall.net"
export DYNDNS_TOKEN="YOUR_TOKEN"

Then run:

scripts/dyndns/tools-dyndns.sh

A cron example:

*/5 * * * * DYNDNS_HOST=home.dyn.tornevall.net DYNDNS_TOKEN=YOUR_TOKEN /path/to/tools-dyndns.sh >/dev/null 2>&1

Windows updater

The Windows client is stored in:

scripts/dyndns/tools-dyndns.bat

Set DYNDNS_HOST and DYNDNS_TOKEN in the environment or in the scheduled task configuration, then run the BAT file through Windows Task Scheduler.

Database migration policy

Dynamic DNS migrations follow the Tools production migration rules:

  • tables are created only when they do not already exist
  • table alterations are only performed after confirming that the table exists
  • no down() migration is provided

The initial migration creates:

dyndns_zones
dyndns_hosts
dyndns_updates

Dynamic DNS update tokens reuse the existing api_keys table, with one tornevall_dyndns key per user.