# nxdns A self-hosted DNS sinkhole for a household LAN, written in Zig 0.16. One static musl binary, SQLite for state, a Raspberry Pi 5 as the reference target. It answers your network's DNS, blocks what you tell it to, and shows you what asked for what. ## Features - Blocklist filtering: subscribe to hosts/domain lists, plus your own allow and block rules with wildcard support (`*.example.com`) - Per-client policy groups: different filtering for the kids' tablet and your workstation - Local DNS records and conditional forwarding for internal zones - Encrypted upstreams: DNS-over-HTTPS and DNS-over-TLS with failover - Built-in DoH and DoT server endpoints, with certificate hot-reload - Bounded in-memory DNS cache with TTL-respecting expiry - Query log with retention limits, live-streamed over SSE - Web UI (embedded in the binary) and a REST API with a served OpenAPI spec - Prometheus-style `/metrics`, per-client rate limiting, disk-full self-protection ## Quickstart (docker compose) Build the binary and image, seed a minimal configuration, start it: ```sh (cd web && npm ci && npm run build) zig build cross -Dweb-dist=web/dist -Doptimize=ReleaseSafe cd deploy/docker mkdir -p etc-nxdns cat > etc-nxdns/config.zon <<'EOF' .{ .groups = .{ .{ .name = "default" } }, .upstreams = .{ .{ .url = "https://cloudflare-dns.com/dns-query" } }, .web = .{ .password = "choose-a-real-password" }, } EOF docker compose up -d ``` DNS is on port 53, the web UI on . The config file seeds the database on first boot only; from then on the database is the truth and changes go through the UI, the API, or `nxdns export` / `nxdns import`. Full install instructions, including the systemd path and the Pi 5 recipe, are in [docs/how-to/install-with-systemd.md](docs/how-to/install-with-systemd.md) and [docs/how-to/install-with-docker.md](docs/how-to/install-with-docker.md). ## Building from source Requires [Zig 0.16.0](https://ziglang.org/download/) and Node.js 24 (for the web UI). C dependencies (SQLite, mbedTLS) are vendored and built by `zig build`. ```sh (cd web && npm ci && npm run build) # web UI -> web/dist zig build -Dweb-dist=web/dist # native binary -> zig-out/bin/nxdns zig build cross -Dweb-dist=web/dist -Doptimize=ReleaseSafe # static x86_64 + aarch64 musl binaries zig build test --summary all # unit tests ``` ## Documentation Start at [docs/README.md](docs/README.md), which splits the documentation into a tutorial, how-to guides, reference and explanation. - [docs/tutorial/first-run.md](docs/tutorial/first-run.md) — build it, resolve a name, block a domain, on a scratch directory - [docs/how-to/install-with-systemd.md](docs/how-to/install-with-systemd.md) — a real install, including the Raspberry Pi 5 - [docs/reference/configuration.md](docs/reference/configuration.md) — every configuration field - [docs/reference/api.md](docs/reference/api.md) — REST API, auth and SSE - [docs/reference/cli.md](docs/reference/cli.md) — subcommands, flags and exit codes - [docs/explanation/architecture.md](docs/explanation/architecture.md) — module map and design - [PLAN.md](PLAN.md) and [specs/](specs/) — scope, design decisions and per-milestone contracts