Standalone Server / VPS Guide
DNS Worker can run completely independent of Cloudflare Workers on your own VPS, home server, or virtual machine.
System Requirements
Section titled “System Requirements”- Runtime (Node.js / Bun):
- Node.js:
>= 22.5.0(Recommended, LTS with built-innode:sqlite) - Bun:
>= 1.4.0(Supported with built-innode:sqlitecompatibility layer)
- Node.js:
- Memory: Minimum 256MB RAM (512MB+ recommended)
- Network Ports:
- UDP 53 (Classic DNS, optional)
- TCP 853 (DoT, optional, requires wildcard certificate)
- TCP 10080 (HTTP Web Dashboard & DoH)
- TCP 10443 (HTTPS Web Dashboard & DoH, optional, requires certificate)
Directory Standards
Section titled “Directory Standards”DNS Worker automatically manages standard persistent directories:
- Linux:
- Configuration:
/etc/dns-worker/.env - Database:
/var/lib/dns-worker/dns_worker.sqlite
- Configuration:
- Windows:
- Configuration & Data:
%ProgramData%\DNS-Worker\(e.g.C:\ProgramData\DNS-Worker\.env)
- Configuration & Data:
Manage configuration effortlessly with the CLI:
# View active configuration pathsdns-worker config show
# Initialize clean standard .env filedns-worker config initDocker Deployment (Bun LTS Runtime)
Section titled “Docker Deployment (Bun LTS Runtime)”DNS Worker provides an official containerized workflow powered by Bun LTS (oven/bun:1-slim) for minimal memory footprint and instant startup.
Quick Run with Docker
Section titled “Quick Run with Docker”Run the container in detached mode with persistent volumes for database, configuration, and TLS certificates:
docker run -d \ --name dns-worker \ --restart unless-stopped \ -p 53:53/udp \ -p 853:853/tcp \ -p 80:80/tcp \ -p 443:443/tcp \ -v dns_worker_data:/var/lib/dns-worker \ -v dns_worker_config:/etc/dns-worker \ -v /etc/letsencrypt:/etc/ssl/dns-worker:ro \ hugokoo/dns-worker:latest[!TIP] HTTPS Auto-Redirection: Direct use of plain HTTP is not recommended in production. When TLS certificates are mounted to
/etc/ssl/dns-worker(or configured viaSERVERFULL_TLS_CERT_PATH), DNS Worker activates HTTPS on port 443, and all plain HTTP requests arriving on port 80 will automatically redirect to HTTPS (HTTP 301/307).
Docker Volume & Port Reference
Section titled “Docker Volume & Port Reference”- Ports:
53:53/udp: Classic UDP DNS (RFC 1035)853:853/tcp: DNS over TLS (DoT, RFC 7858, DoQ compatible)80:80/tcp: HTTP Web Dashboard (Auto-redirects to HTTPS 443)443:443/tcp: HTTPS Web Dashboard & DoH (Primary / Recommended)
- Volumes:
/var/lib/dns-worker: Holds persistent SQLite database (dns_worker.sqlite) and auto-generated JWT secrets./etc/dns-worker: Mount host directory to provide custom.envconfiguration file./etc/ssl/dns-worker: Mount host TLS certificates (fullchain.pemandprivkey.pem) for automatic discovery and HTTPS activation.
Building & Publishing to Docker Hub
Section titled “Building & Publishing to Docker Hub”Images can be published automatically via GitHub Actions upon pushing Git release tags (v*), or manually built using CLI scripts:
# Build local images with auto-taggingnpm run docker:build
# Build multi-platform images (linux/amd64, linux/arm64) and push to Docker Hubnpm run docker:multiarch -- --push
# Push existing local tags to Docker Hubnpm run docker:pushPorts & Network Configuration
Section titled “Ports & Network Configuration”Customize listening ports in /etc/dns-worker/.env:
# Network interface binding (0.0.0.0 binds all interfaces, or 127.0.0.1 for local-only)SERVERFULL_HOST=0.0.0.0
# Port configurationSERVERFULL_UDP_PORT=53SERVERFULL_DOT_PORT=853SERVERFULL_HTTP_PORT=10080SERVERFULL_HTTPS_PORT=10443
# Toggle specific listenersSERVERFULL_DISABLE_HTTPS=falseReverse Proxying HTTP & DoH (Caddy / Nginx)
Section titled “Reverse Proxying HTTP & DoH (Caddy / Nginx)”In production deployments, you can place a mature reverse proxy such as Caddy or Nginx in front of DNS Worker instead of exposing port 10080 (HTTP) directly or managing local certificates on port 10443 (HTTPS).
The reverse proxy terminates TLS on standard port 443 (with automated Let’s Encrypt / ZeroSSL certificates) and forwards traffic to http://127.0.0.1:10080.
[!TIP] When using a reverse proxy, set
SERVERFULL_DISABLE_HTTPS=truein.envto disable the internal port 10443 listener and save system resources. You can also bindSERVERFULL_HOST=127.0.0.1so port10080is accessible strictly via localhost.
Option 1: Caddy Configuration (Recommended)
Section titled “Option 1: Caddy Configuration (Recommended)”Caddy provides zero-configuration automated HTTPS with automatic renewal. Add this to /etc/caddy/Caddyfile:
dns.example.com { reverse_proxy 127.0.0.1:10080 { header_up Host {host} header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} header_up CF-Connecting-IP {remote_host} }}[!NOTE] DNS Worker automatically inspects
CF-Connecting-IP,X-Real-IP, andX-Forwarded-For(leftmost IP) on proxied HTTP requests. DNS query logs, user session lists, and security audits will accurately record the client’s external IP address instead of127.0.0.1.
Reload Caddy:
sudo systemctl reload caddyOption 2: Nginx Configuration
Section titled “Option 2: Nginx Configuration”If you use Nginx, add the following server block (e.g., /etc/nginx/sites-available/dns-worker):
server { listen 80; server_name dns.example.com; return 301 https://$host$request_uri;}
server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name dns.example.com;
ssl_certificate /etc/letsencrypt/live/dns.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/dns.example.com/privkey.pem;
# DoH and Web Dashboard reverse proxy location / { proxy_pass http://127.0.0.1:10080; proxy_http_version 1.1;
proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support (for live dashboard updates) proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }}Reload Nginx:
sudo nginx -t && sudo systemctl reload nginx[!NOTE] Client IP Forwarding: Forwarding
X-Real-IPandX-Forwarded-Foris essential so that DNS Worker correctly records real client IPs, evaluates rate limits, and resolves geographic coordinates in query logs.
Maintenance & Factory Reset
Section titled “Maintenance & Factory Reset”If you need to restore the system to its initial state, use the reset command:
# Interactive reset (requires secondary confirmation)dns-worker reset
# Automated / non-interactive resetdns-worker reset --forceThis operation will:
- Restore the
.envconfiguration file to the built-in default template. - Completely clear the SQLite database and reapply all migrations from scratch.
