runbound 0.4.6

RFC-compliant DNS resolver — drop-in Unbound with REST API, ACME auto-TLS, HMAC audit log, and master/slave HA
# ─────────────────────────────────────────────────────────────────────────────
# Runbound — Slave replica configuration
#
# Use-case : High-availability DNS — this node is a read-only replica of a
#            master Runbound instance.
#
# How it works:
#   - The slave polls the master every sync-interval seconds via HTTPS.
#   - On first start: TOFU handshake — cert fingerprint is downloaded from
#     GET /sync/cert, cross-verified against the TLS handshake, then saved to
#     /etc/runbound/sync-master.fingerprint (chmod 640). A WARN is emitted.
#     Verify the fingerprint manually: compare with `openssl x509 -fingerprint
#     -sha256 -noout -in /etc/runbound/sync-cert.pem` on the master.
#   - All subsequent connections pin the saved fingerprint (rustls, no CA).
#   - Delta events (DNS adds/deletes, blacklist, feeds) are applied live.
#   - If > 1 000 events behind (410 Gone): full snapshot sync is performed.
#   - All non-GET API requests return 503 READ_ONLY on slave nodes.
#
# Companion master config: see examples/master.conf or the docs/configuration.md
# ─────────────────────────────────────────────────────────────────────────────

server:
    # ── Network ──────────────────────────────────────────────────────────────
    interface:  0.0.0.0
    port:       53

    do-ip4:     yes
    do-ip6:     yes
    do-udp:     yes
    do-tcp:     yes

    # ── Access control ────────────────────────────────────────────────────────
    # Same rules as the master — LAN clients query this node identically.
    access-control: 127.0.0.0/8      allow
    access-control: 192.168.1.0/24   allow   # adjust to your subnet
    access-control: 10.0.0.0/8       allow
    access-control: 0.0.0.0/0        refuse

    # ── Rate limiting ─────────────────────────────────────────────────────────
    rate-limit:    200
    cache-max-ttl: 3600

    # ── DNS rebinding protection ──────────────────────────────────────────────
    private-address: 10.0.0.0/8
    private-address: 172.16.0.0/12
    private-address: 192.168.0.0/16
    private-address: 127.0.0.0/8
    private-address: fd00::/8

    # ── Slave/master replication ──────────────────────────────────────────────
    mode:          slave

    # IP:port of the master's sync HTTPS server (sync-port on the master).
    sync-master:   192.168.1.10:8082

    # Shared Bearer token — must match the master's sync-key.
    # Prefer setting via environment variable if possible:
    #   export RUNBOUND_SYNC_KEY="$(cat /etc/runbound/sync.key)"
    sync-key:      "change-me-to-match-master"

    # Poll interval in seconds (default: 30).
    # Lower values reduce replication lag; higher values reduce load.
    sync-interval: 30

    # ── REST API ──────────────────────────────────────────────────────────────
    # The REST API is available on slave nodes in read-only mode.
    # GET endpoints (dns, blacklist, feeds, stats, logs, upstreams…) work normally.
    # POST and DELETE requests are rejected with 503 READ_ONLY.
    api-port: 8081
    # api-key is auto-generated at startup and saved to /etc/runbound/api.key
    # Override with RUNBOUND_API_KEY environment variable.

    # ── Memory guard (always active — no config needed) ───────────────────────
    # At ≥ 80 % system RAM: rate-limiter + resolver cache purged automatically.
    # Inflight semaphore: max 4 096 concurrent requests → REFUSED if exceeded.

    # ── Logging ───────────────────────────────────────────────────────────────
    verbosity: 1
    # logfile: /var/log/runbound/runbound.log

# ── Upstream resolvers ────────────────────────────────────────────────────────
# Same forward-zone as the master so both nodes resolve identically.
forward-zone:
    name:                 "."
    forward-addr:         1.1.1.1@853
    forward-addr:         1.0.0.1@853
    forward-tls-upstream: yes