runbound 0.3.3

RFC-compliant DNS resolver — drop-in Unbound with REST API, ACME auto-TLS, HMAC audit log, and master/slave HA
# ─────────────────────────────────────────────────────────────────────────────
# Runbound — Home / Pi-hole replacement configuration
#
# Use-case : Raspberry Pi / home router running a LAN DNS resolver.
# - Blocks ads & telemetry via the REST API feed system
# - Serves custom local hostnames (NAS, printer, cameras…)
# - Forwards everything else to Cloudflare with DNSSEC validation
# ─────────────────────────────────────────────────────────────────────────────

server:
    # Listen on all interfaces so LAN clients can reach the resolver.
    # On Raspberry Pi replace 0.0.0.0 with the Pi's LAN IP for clarity.
    interface:  0.0.0.0
    port:       53

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

    # ── Access control ───────────────────────────────────────────────────────
    # Allow only LAN + loopback; refuse everything else (internet scanners).
    access-control: 127.0.0.0/8      allow
    access-control: 192.168.1.0/16   allow   # common home subnet
    access-control: 10.0.0.0/8       allow   # some ISP boxes use 10.x
    access-control: 0.0.0.0/0        refuse

    # ── Rate limiting ────────────────────────────────────────────────────────
    # 200 q/s per source IP is generous for residential use.
    rate-limit:    200
    cache-max-ttl: 3600   # cap TTLs at 1 hour — faster recovery after IP change

    # ── DNS rebinding protection ─────────────────────────────────────────────
    # Prevents a malicious public domain from resolving to a private LAN IP.
    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

    # ── Local hostnames ──────────────────────────────────────────────────────
    local-zone: "home." static

    local-data: "nas.home.       300 IN A 192.168.1.10"
    local-data: "printer.home.   300 IN A 192.168.1.20"
    local-data: "camera1.home.   300 IN A 192.168.1.30"
    local-data: "camera2.home.   300 IN A 192.168.1.31"
    local-data: "router.home.    300 IN A 192.168.1.1"
    local-data: "pi.home.        300 IN A 192.168.1.5"

    # Reverse DNS for the NAS (optional but handy for logs)
    local-zone: "1.168.192.in-addr.arpa." static
    local-data: "10.1.168.192.in-addr.arpa. 300 IN PTR nas.home."

    # ── Memory guard (always active — no config needed) ─────────────────────
    # /proc/meminfo is checked every 30 s.
    # At ≥ 80 % RAM usage → rate-limiter DashMap cleared + DNS resolver rebuilt
    # (in-flight queries are unaffected via ArcSwap). WARN emitted in logs.
    # Inflight semaphore: max 4 096 concurrent requests → REFUSED beyond that.

    # ── Logging ─────────────────────────────────────────────────────────────
    # Remove or set to "" to log to stdout (easier with systemd journal).
    # logfile: /var/log/runbound/runbound.log

# ── Upstream resolver — Cloudflare DoT (encrypted, privacy-friendly) ─────────
forward-zone:
    name:                 "."
    forward-addr:         1.1.1.1@853
    forward-addr:         1.0.0.1@853
    forward-tls-upstream: yes