milestone 11: systemd and docker packaging, operator and architecture docs, config and api reference, docs drift guards

This commit is contained in:
2026-08-02 15:24:10 +02:00
parent a589df7515
commit bdb6ffab7a
29 changed files with 1936 additions and 94 deletions
+6
View File
@@ -0,0 +1,6 @@
# The Dockerfile copies only zig-out/cross out of the repository-root context,
# and BuildKit transfers only referenced paths. This file guards the classic
# (non-BuildKit) builder, which would otherwise send the whole tree: copy it to
# the repository root as .dockerignore before building without BuildKit.
*
!zig-out/cross
+33
View File
@@ -0,0 +1,33 @@
# The binary is NOT compiled here. Build it first, from the repository root:
#
# (cd web && npm ci && npm run build)
# zig build cross -Dweb-dist=web/dist -Doptimize=ReleaseSafe
#
# then build the image with the repository root as context:
#
# docker build -t nxdns -f deploy/docker/Dockerfile .
#
# The builder stage stages the CA bundle (upstream DoH/DoT verification rescans
# the system store; a scratch image without one breaks every TLS upstream) and
# maps the buildx TARGETARCH onto the zig cross-target directory.
FROM alpine:3.22 AS builder
RUN apk add --no-cache ca-certificates
ARG TARGETARCH
COPY zig-out/cross /cross
RUN mkdir -p /rootfs/etc/ssl/certs /rootfs/etc/nxdns /rootfs/var/lib/nxdns \
&& cp /etc/ssl/certs/ca-certificates.crt /rootfs/etc/ssl/certs/ \
&& case "${TARGETARCH:-amd64}" in \
amd64) cp /cross/x86_64-linux-musl/nxdns /rootfs/nxdns ;; \
arm64) cp /cross/aarch64-linux-musl/nxdns /rootfs/nxdns ;; \
*) echo "unsupported TARGETARCH '${TARGETARCH}'" >&2; exit 1 ;; \
esac \
&& chown 65532:65532 /rootfs/var/lib/nxdns
FROM scratch
COPY --from=builder /rootfs/ /
USER 65532:65532
VOLUME /var/lib/nxdns
EXPOSE 53/udp 53/tcp 8080 443 853
ENTRYPOINT ["/nxdns"]
CMD ["run"]
+31
View File
@@ -0,0 +1,31 @@
services:
nxdns:
image: nxdns
build:
context: ../..
dockerfile: deploy/docker/Dockerfile
restart: unless-stopped
# First boot needs ./etc-nxdns/config.zon with a `default` group and at
# least one enabled upstream, or the container exits with code 2. The file
# seeds the database once; after that the database is the truth and the
# file is ignored.
volumes:
- ./etc-nxdns:/etc/nxdns:ro
- nxdns-data:/var/lib/nxdns
ports:
- "53:53/udp"
- "53:53/tcp"
- "8080:8080"
# DoH/DoT listeners, off by default in the config:
# - "443:443"
# - "853:853"
# Per-network-namespace sysctl: lets uid 65532 bind port 53 inside the
# container without CAP_NET_BIND_SERVICE.
sysctls:
net.ipv4.ip_unprivileged_port_start: 0
# Do not point the host's resolv.conf at nxdns itself: the container's own
# lookups (upstream DoH/DoT hostnames) would then depend on the service
# they are trying to start.
volumes:
nxdns-data:
+49
View File
@@ -0,0 +1,49 @@
[Unit]
Description=nxdns DNS sinkhole
Documentation=https://git.mial.net/mokhtar/nxdns
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=nxdns
Group=nxdns
ExecStart=/usr/local/bin/nxdns run
# nxdns logs to stderr by default; systemd captures it into the journal.
StateDirectory=nxdns
StateDirectoryMode=0700
LogsDirectory=nxdns
ConfigurationDirectory=nxdns
# Port 53 (and 443/853 when the DoH/DoT listeners are enabled).
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
ProtectClock=yes
ProtectHostname=yes
ProtectProc=invisible
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
UMask=0077
SystemCallFilter=@system-service
SystemCallArchitectures=native
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.target
+1
View File
@@ -0,0 +1 @@
u nxdns - "nxdns DNS sinkhole"