This guide details how to build, run, and host the LLM over DNS server in production environments using Docker and Docker Compose.
The project includes an optimized multi-stage Dockerfile to produce secure, minimal production container images:
--release).ca-certificates) into a minimal debian:bookworm-slim base image.
app) to prevent host system exposure.~45MB.Using Docker Compose is the recommended way to deploy and maintain the server.
docker-compose.ymlCreate a docker-compose.yml file in your deployment directory:
version: '3.8'
services:
llm-dns:
image: ghcr.io/duyet/llm-over-dns:latest
container_name: llm-dns
restart: unless-stopped
ports:
# Maps host port 53 (UDP) to container port 5353
- "53:5353/udp"
environment:
- ANYROUTER_API_KEY=${ANYROUTER_API_KEY}
- ANYROUTER_MODEL=google/gemini-2.5-flash-lite,meta/llama-3.2-3b-instruct
- DNS_PORT=5353
- DNS_ADDRESS=0.0.0.0
- RUST_LOG=info
env_file:
- .env
Create a local .env file alongside your compose file:
# Required: AnyRouter API Key (Recommended)
ANYROUTER_API_KEY=sk-ar-v1-your-key-here
# Or OpenRouter:
# OPENROUTER_API_KEY=sk-or-v1-your-key-here
Start the container in detached background mode:
# Start
docker compose up -d
# Check startup logs
docker compose logs -f
# Stop
docker compose down
If you prefer building and running the container manually:
docker build -t llm-over-dns:latest .
docker run -d \
--name llm-dns \
--restart unless-stopped \
-p 53:5353/udp \
-e ANYROUTER_API_KEY="sk-ar-v1-yourkey" \
-e DNS_PORT=5353 \
llm-over-dns:latest
Deploying DNS servers in production requires attention to network binding:
Port 53 is a privileged port on Linux hosts. Rather than running the Docker container with root privileges, we bind the host UDP port 53 directly to a high, non-privileged port inside the container (e.g. -p 53:5353/udp).
Most Linux distributions (like Ubuntu Server) run a local resolver (systemd-resolved) that already binds to port 53 on the loopback interface.
To verify if port 53 is blocked:
sudo lsof -i :53
If systemd-resolved is blocking the port, edit /etc/systemd/resolved.conf:
[Resolve]
DNSStubListener=no
Then restart the service:
sudo systemctl restart systemd-resolved
Ensure that UDP port 53 is explicitly allowed in your cloud provider’s firewall policy (and on-server firewall like UFW):
sudo ufw allow 53/udp