mokhtar 9f8a5cd753
CI / test (push) Failing after 1m12s
CI / test-aarch64 (push) Failing after 2m27s
CI / frontend (push) Successful in 1m28s
CI / cross (push) Failing after 27s
CI / docker (push) Failing after 24s
milestone 15: make a green run mean a real pass
2026-08-07 01:28:13 +02:00

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:

(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 http://localhost:8080. 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 and docs/how-to/install-with-docker.md.

Building from source

Requires Zig 0.16.0 and Node.js 24 (for the web UI). C dependencies (SQLite, mbedTLS) are vendored and built by zig build.

(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, which splits the documentation into a tutorial, how-to guides, reference and explanation.

S
Description
No description provided
Readme EUPL-1.2
2.4 MiB
v0.0.1
Latest
2026-08-08 23:26:44 +00:00
Languages
Zig 89.5%
TypeScript 9.8%
JavaScript 0.4%
Dockerfile 0.1%