Skip to content
Source: docs/deployment.md
Commit: ca917b62635321a15d79f190225b7cff9acc1bc9
Source updated:  ·  Edit this page

Production deployment model

This document describes a generic two-node RillDNS deployment. All names and addresses are examples from domains and networks reserved for documentation.

Topology

Node Example address Role
dns-primary 192.0.2.10 Writable authoritative primary and failback resolver
dns-secondary 192.0.2.11 Read-only replica and normal DNS traffic endpoint
DNS VIP 192.0.2.53 Client-facing address managed by keepalived or an equivalent mechanism
reverse-proxy 192.0.2.30 TLS termination for https://dns.example.net
Prometheus 192.0.2.20 Scrapes each node's read-only metrics endpoint

Both nodes run CoreDNS and the RillDNS API. The primary API accepts changes; the secondary API is explicitly read-only. Keep the management API on loopback, expose the UI only through an authenticated reverse proxy, and limit the metrics listener to the monitoring network.

Keepalived provides automatic DNS VIP movement based on local service health. Configure the HTTPS reverse proxy with the primary UI listener as its normal upstream and the secondary as a backup. This preserves read-only management visibility during a primary failure without treating VIP ownership as writer election. Automatic writer promotion requires independent fencing or quorum and is not part of the two-node reference deployment.

Replication

The primary publishes validated zone files atomically and sends DNS NOTIFY to the secondary. The persistent rill-secondary daemon compares SOA serials and requests a TSIG-authenticated AXFR from a cache-free authority when a serial changes. An hourly SOA poll covers lost NOTIFY messages.

dns-primary:1056 -- TSIG AXFR/NOTIFY --> dns-secondary:1054

Generate the shared TSIG secret during deployment. Install it as root-owned data on the two nodes; never store it in Git. Restrict the NOTIFY, transfer, and read-only configuration endpoints to the peer addresses with a host firewall.

Blocking and telemetry

Each node downloads and compiles configured hosts/domain lists. Publication is atomic and refuses an unexpectedly small result, preserving the last known good snapshot on failure.

CoreDNS sends client-query dnstap frames over loopback to rill-telemetry. Optional rilldns_additional_dnstap_endpoints add passive TCP consumers while leaving that privacy-preserving local analytics path intact. Keep real collector addresses in the ignored deployment inventory. The collector compares names with the in-memory block set and always exports aggregate total and blocked counters. Query analytics have three explicit modes:

  • aggregate is the default and immediately discards query names and client addresses;
  • statistics retains bounded five-minute domain, client, blocked-domain, and query-type counters for Pi-hole-style rankings;
  • detailed adds a bounded recent-query ring to the statistics.

Statistics are atomically checkpointed to a mode-0600 state file once per minute and expired according to the configured retention. Prometheus continues to store aggregate rates only; domain and client names are never used as metric labels. The loopback analytics endpoint is proxied through the authenticated management UI.

Authentication

The browser UI uses standard OIDC Authorization Code flow with PKCE. Configure the issuer, client credentials, exact callback URL, allowed identities, and a shared encrypted-session key in a root-owned environment file. Pocket ID is one compatible provider; any conforming OIDC provider should work.

Operations

  • Validate primary zones every five minutes.
  • Refresh blocklists daily with randomized delay.
  • Run the TSIG-authenticated primary/secondary differential check hourly.
  • Alert on stale or failed refreshes, undersized blocklists, differential mismatches, and stale differential results.
  • Back up zone files, role metadata, audit records, and generated secrets.
  • Test failover and restoration before making the VIP the only client path.

The files under deploy/systemd, deploy/nginx, and deploy/prometheus are examples. Adapt addresses, firewall policy, paths, users, and service dependencies to your environment.

Tagged releases

Tags matching v* run the same test and build checks as pull requests, build static linux/amd64 and linux/arm64 command bundles, publish checksums and a GitHub Release. GitHub Actions has no host credentials and performs no deployment. Production deployment remains an explicit Ansible operation from the private operations environment, where inventory, secrets, rollout order, health checks, and rollback policy belong.

Create releases only from protected main, for example:

git tag -s v0.1.0 -m 'RillDNS v0.1.0'
git push origin v0.1.0