Docker

  1. Build the image
  2. Run a single node
  3. docker-compose
  4. Port 53 on the host
  5. Health and metrics
  6. Upgrading
  7. Next

Build the image

docker build -t dnsmesh-node:latest .

Multi-stage build on python:3.11-slim. Final image runs as a non-root dmp user, exposes 5353/udp and 8053/tcp, and has a HEALTHCHECK that hits /health through curl.

Run a single node

docker run -d --name dnsmesh-node \
  -p 5353:5353/udp -p 8053:8053/tcp \
  -v dnsmesh-data:/var/lib/dmp \
  dnsmesh-node:latest
Mount Purpose
-v dnsmesh-data:/var/lib/dmp Persistent sqlite store (message RRsets, replay state)

Check it’s up:

curl http://127.0.0.1:8053/health    # {"status":"ok"}
curl http://127.0.0.1:8053/metrics   # Prometheus text

docker-compose

docker-compose.yml at the repo root is the local-dev config:

services:
  dnsmesh-node:
    build: .
    ports:
      - "5353:5353/udp"
      - "8053:8053/tcp"
    volumes:
      - dnsmesh-data:/var/lib/dmp
    environment:
      DMP_LOG_LEVEL: INFO
      # (commented-out knobs for rate limits, bearer token, log format)
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://127.0.0.1:8053/health"]
      interval: 30s

volumes:
  dnsmesh-data:

Bring it up:

docker compose up -d
docker compose logs -f dnsmesh-node
docker compose down     # stop; volume persists

Port 53 on the host

Port 53 is privileged on Linux. Three options:

  1. Map the host’s 53 to the container’s 5353 (recommended):
    -p 53:5353/udp
    

    Your DMP node now answers real DNS queries for configured names. The container itself still binds 5353 internally.

  2. Run the container with CAP_NET_BIND_SERVICE and set DMP_DNS_PORT=53. Requires --cap-add=NET_BIND_SERVICE.
  3. Stay on 5353 for dev. Easier, but external resolvers won’t query you automatically.

Most Linux distros’ systemd-resolved holds port 53 out of the box. Free it with:

sudo systemctl disable --now systemd-resolved
sudo rm /etc/resolv.conf
echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf

Health and metrics

  • GET /health — 200 with {"status":"ok"} when sqlite is reachable; 503 with {"status":"degraded"} otherwise. Use this for your orchestrator’s liveness probe.
  • GET /metrics — Prometheus text format. Exposes:
    • dmp_http_requests_total{method,status}
    • dmp_dns_queries_total{outcome} (outcome ∈ noerror/nxdomain/…/rate_limited)
    • dmp_records (gauge — live records in the sqlite store)
  • GET /stats — JSON {"records": <count>}. Same info as the gauge, for humans.

Upgrading

git pull
docker build -t dnsmesh-node:latest .
docker compose up -d dnsmesh-node

The sqlite schema migrates itself on open — no manual step. Existing records keep their TTLs; clients keep their replay caches.

Next