Runbook
import { Aside } from ‘@astrojs/starlight/components’;
Health checks
Section titled “Health checks”GET /api/v1/health → { "status": "ok" }GET /api/v1/version → { "version": "...", "buildTime": "...", "debug": false }GET /api/v1/stats → cache/filter/health snapshotIf /health returns non-200 or times out, restart the daemon (systemd auto-restarts on failure by default).
# systemdjournalctl -u homedns -n 100systemctl restart homedns
# Check forwarder health via CLIdnsctl healthRecursion vs forwarding
Section titled “Recursion vs forwarding”Without at least one of these configured, all resolution for non-local zones fails with SERVFAIL:
| Option | How to enable |
|---|---|
| Full recursive resolver | recursion.enabled: true in YAML |
| Static YAML forwarder | forwarders.servers[...] in YAML |
| API/UI conditional forwarder | Forwarders page or dnsctl forwarders add |
Adding a zone
Section titled “Adding a zone”# Create zone and add recordsdnsctl zones create example.comdnsctl records add example.com 'www.example.com. 300 IN A 192.0.2.1'dnsctl records add example.com 'mail.example.com. 300 IN A 192.0.2.2'
# Export as zone filednsctl zones export example.comOr via the web admin: Zones → New zone (wizard mode creates SOA, NS, and optional A record in one flow).
Adding a blocklist
Section titled “Adding a blocklist”dnsctl filter add --name stevenblack \ --url https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts \ --format 1dnsctl filter refreshdnsctl filter test ads.doubleclick.netSupported list formats: hosts, domain-only, AdBlock, dnsmasq, auto. Or via the web admin: Filter → Add source.
Adding a conditional forwarder
Section titled “Adding a conditional forwarder”dnsctl forwarders add --id corp --upstream 10.0.0.53:53 --strategy parallelAvailable strategies:
| Strategy | Behaviour |
|---|---|
failover | Try each upstream in order; fall back on error |
round_robin | Rotate through upstreams |
random | Pick randomly |
parallel | Race all; first valid answer wins, cancel losers |
hedged | Staggered race — fire next upstream after a delay derived from observed latency |
Health-aware: failing upstreams are skipped by all strategies.
Config reload
Section titled “Config reload”File-watch reload is enabled by default. Overwrite the config file in place and homeDNS will pick up the new values. Reload can also be triggered from the web admin: Server → Reload.
Backup and restore
Section titled “Backup and restore”Memory storage
Section titled “Memory storage”Ephemeral by design — treat as a runtime cache. Data does not survive restarts.
SQLite storage
Section titled “SQLite storage”# Safe live backup (WAL mode)cp data/homedns.db data/homedns.db.bakOr download via API/web admin: Backup page → download blob.
Restore: upload a backup via Backup → Restore (supports dry-run) or replace the .db file while the daemon is stopped.
Upgrading
Section titled “Upgrading”- Stop the daemon (
systemctl stop homedns) - Replace
bin/dnsdandbin/dnsctl - Start the daemon (
systemctl start homedns) - Watch logs for schema migration messages
Schema migrations are forward-only. Downgrading after a migration requires a fresh database (restore from pre-upgrade backup).
Troubleshooting table
Section titled “Troubleshooting table”| Symptom | Likely cause | Fix |
|---|---|---|
All queries return SERVFAIL | No forwarders configured and recursion disabled | Add a forwarder or set recursion.enabled: true |
| Management API returns 403 | Caller IP outside management.allow_cidrs | Adjust CIDR list or call from allowed network |
Filter decide always returns Allow | No list loaded yet (first refresh pending) | Run dnsctl filter refresh or wait for scheduler |
High latency on parallel strategy | Slow upstream not yet classified as failing | Check dnsctl health; tune forwarding.health.slow_above |
| Restart loops in systemd | Invalid config syntax | Run ./bin/dnsd --config /etc/homedns/config.yaml standalone and check stderr |
nsupdate returns REFUSED | DDNS policy not configured or wrong mode/CIDRs/keys | dnsctl policy get <zone> and adjust |
nsupdate returns NOTAUTH | Key name or secret mismatch | Re-add via dnsctl tsig add with correct algorithm |
Observability
Section titled “Observability”| Source | Detail |
|---|---|
| Structured logs | logging.format: json for production — pipe to your log aggregator |
| Live query log | GET /api/v1/queries/stream (SSE) or Queries page in web admin |
| Stats stream | GET /api/v1/stats/stream (SSE) — rolling QPS/cache/filter counters |
| Forwarder health | GET /api/v1/forwarders/health/stream (SSE) — health and latency updates |
Prometheus /metrics endpoint is on the roadmap; GET /api/v1/stats covers operational monitoring in v1.