Database Deployment & Storage Modes
DNS Worker features a unified Data Access Layer (DAL) abstraction, supporting three distinct database storage engines across Cloudflare 300+ global edge locations, self-hosted Linux VPS servers, Docker containers, and hybrid distributed setups.
┌──────────────────────────────────────────────────────────────────┐│ DNS Worker Data Access Layer (DAL) │└──────────────┬───────────────────┬───────────────────┬───────────┘ │ │ │ ▼ ▼ ▼ ┌────────────────────┐ ┌────────────────┐ ┌────────────────────┐ │ Cloudflare D1 │ │ Turso / libSQL │ │ Local File SQLite │ │ (Serverless Default│ │(Multi-Node Sync│ │(Serverfull Default │ └────────────────────┘ └────────────────┘ └────────────────────┘1. Storage Modes Comparison Matrix
Section titled “1. Storage Modes Comparison Matrix”| Dimension / Mode | ☁️ Mode 1: Cloudflare D1 | 🌐 Mode 2: Turso / libSQL | 🖥️ Mode 3: Local File SQLite |
|---|---|---|---|
| Environment Variable | DATABASE_SERVICE="D1" |
DATABASE_SERVICE="Turso" |
DATABASE_SERVICE="File" |
| Target Runtime | Cloudflare Workers Edge | Cross-Platform Universal (Workers + VPS) | Linux / VPS / Docker / Windows |
| Storage Medium | Edge-managed distributed SQLite | libSQL Cloud cluster / self-hosted sqld | Local physical NVMe / SSD disk |
| Transport Protocol | In-process Workers context binding | HTTPS / WebSocket (Hrana protocol) | Native VFS file I/O (node:sqlite) |
| Multi-Node Sync | Cloudflare internal replication | Strong Real-Time Sync (Workers & VPS share one DB) | Single host isolated |
| Outbound Requests | None (in-process binding) | Outbound HTTPS queries to Turso endpoint | None (zero network traffic) |
| Schema Migrations | Executed via wrangler d1 migrations |
Auto-applied idempotently on startup/request | Auto-applied idempotently on startup |
| Operational Effort | Zero server maintenance | Minimal (Cloud DB instance) | Zero external dependencies |
2. Mode 1: Cloudflare D1 Distributed Database
Section titled “2. Mode 1: Cloudflare D1 Distributed Database”Cloudflare D1 is Cloudflare’s native serverless SQL database built on SQLite, co-located within the same edge data center running your Worker.
Best For
Section titled “Best For”- Standalone serverless DoH deployments running entirely on Cloudflare infrastructure;
- Zero-maintenance high availability out-of-the-box;
- Environments relying solely on Cloudflare Workers and standard free tier quotas.
Setup & Configuration
Section titled “Setup & Configuration”1. Create D1 Database
Section titled “1. Create D1 Database”Run Wrangler CLI in your terminal (or create via Cloudflare Web Dashboard):
# Create production D1 databasenpx wrangler d1 create dns_worker_dbThe CLI will output the database name and a unique database_id (UUID format).
2. Configure wrangler.toml
Section titled “2. Configure wrangler.toml”Add the D1 database binding in wrangler.toml:
[[d1_databases]]binding = "DB"database_name = "dns_worker_db"database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"migrations_dir = "migrations"3. Execute Migrations
Section titled “3. Execute Migrations”# Local development environment migrationnpm run db:migrate:dev
# Remote production Cloudflare D1 migrationnpm run db:migrate:prod4. Environment Variable Configuration (Optional)
Section titled “4. Environment Variable Configuration (Optional)”When running on Cloudflare Workers without DATABASE_SERVICE specified, the system automatically defaults to D1. You may also explicitly define it:
[vars]DATABASE_SERVICE = "D1"3. Mode 2: Turso / libSQL Cloud Database
Section titled “3. Mode 2: Turso / libSQL Cloud Database”Turso is a distributed database powered by libSQL (the modern open-source evolution of SQLite), delivering fast HTTP and WebSocket queries via the lightweight Hrana pipeline protocol.
Core Value: Unified Multi-Node Synchronization
Section titled “Core Value: Unified Multi-Node Synchronization”If you deploy both Cloudflare Workers edge instances and one or more self-hosted VPS (Serverfull) instances:
- D1 cannot be accessed from outside Cloudflare Workers;
- Local SQLite files are strictly bounded to individual VPS disks;
- Turso bridges this gap completely: whether queries hit your Hong Kong VPS, Frankfurt VPS, or Cloudflare Anycast edge, all nodes query and write to the same Turso database in real-time, providing unified user accounts, synchronized custom rules, shared access points, and consolidated query analytics.
Setup & Configuration
Section titled “Setup & Configuration”1. Create a Turso Database
Section titled “1. Create a Turso Database”- Install Turso CLI:
Terminal window curl -sSfL https://get.tur.so/install.sh | bash - Authenticate and create a database instance:
Terminal window turso auth loginturso db create dns-worker-db - Retrieve the database URL:
Terminal window turso db show dns-worker-db --url# Example output: libsql://dns-worker-db-yourorg.turso.io - Generate a persistent Auth Token:
Terminal window turso db tokens create dns-worker-db# Outputs a JWT authentication token
2. Configure Cloudflare Workers with Turso
Section titled “2. Configure Cloudflare Workers with Turso”In wrangler.toml:
[vars]DATABASE_SERVICE = "Turso"TURSO_DATABASE_URL = "https://dns-worker-db-yourorg.turso.io"Store your Auth Token as an encrypted secret:
npx wrangler secret put TURSO_AUTH_TOKEN# Paste your generated token3. Configure Standalone Server / VPS (Serverfull) with Turso
Section titled “3. Configure Standalone Server / VPS (Serverfull) with Turso”In /etc/dns-worker/.env (or local .env):
DATABASE_SERVICE=TursoTURSO_DATABASE_URL=libsql://dns-worker-db-yourorg.turso.ioTURSO_AUTH_TOKEN=eyJhbGciOiJFZERTQTEw...your_tokenRestart your service or binary:
sudo systemctl restart dns-worker# ordns-worker start4. Self-Hosted sqld Alternative
Section titled “4. Self-Hosted sqld Alternative”For air-gapped or self-hosted requirements, you can run the open-source tursodatabase/sqld daemon via Docker on your private network:
docker run -d \ --name sqld \ -p 8080:8080 \ -v /data/sqld:/var/lib/sqld \ -e SQLD_AUTH_JWT_KEY="your_public_key" \ tursodatabase/sqld:latestSet TURSO_DATABASE_URL="http://your-sqld-host:8080" in DNS Worker to operate entirely on private infrastructure.
4. Mode 3: Local File SQLite Database
Section titled “4. Mode 3: Local File SQLite Database”For deployments prioritizing total data sovereignty, zero cloud reliance, and offline capability, DNS Worker includes a high-performance local SQLite storage engine.
Architectural Highlights
Section titled “Architectural Highlights”- Zero External Dependencies: Operates on the Node.js standard library module
node:sqlite(built into Node.js>= 22.5.0and Bun>= 1.4.0); - High-Throughput Disk I/O: Configured with
PRAGMA journal_mode = WAL;andPRAGMA synchronous = NORMAL;, offering strong concurrent read/write throughput and crash resiliency; - Complete Privacy: All query logs and credentials reside in a single local
.sqlitefile on your private NVMe disk.
Default Persistent Paths
Section titled “Default Persistent Paths”- Linux / systemd:
/var/lib/dns-worker/dns_worker.sqlite - Windows:
%ProgramData%\DNS-Worker\dns_worker.sqlite
Setup & Configuration
Section titled “Setup & Configuration”1. Standard Environment Configuration (.env)
Section titled “1. Standard Environment Configuration (.env)”In /etc/dns-worker/.env:
DATABASE_SERVICE=File
# Optional: Override default database storage pathSERVERFULL_DB_PATH=/var/lib/dns-worker/dns_worker.sqlite2. Docker Container Persistent Volume
Section titled “2. Docker Container Persistent Volume”When running in Docker, mount the database directory to maintain state across container restarts:
docker run -d \ --name dns-worker \ --restart unless-stopped \ -p 53:53/udp \ -p 853:853/tcp \ -p 10080:10080/tcp \ -p 10443:10443/tcp \ -v /var/lib/dns-worker:/var/lib/dns-worker \ -v /etc/dns-worker:/etc/dns-worker \ ghcr.io/obein/dns-worker:latest3. Backup and Disaster Recovery
Section titled “3. Backup and Disaster Recovery”Backing up local SQLite state is straightforward:
# Online hot backup using sqlite3 CLIsqlite3 /var/lib/dns-worker/dns_worker.sqlite ".backup /backup/dns_worker_$(date +%Y%m%d).sqlite"
# Or copy during maintenance (ensure -wal and -shm files are captured)cp /var/lib/dns-worker/dns_worker.sqlite /backup/5. Engine Resolution Priority & Auto-Detection
Section titled “5. Engine Resolution Priority & Auto-Detection”When DNS Worker starts, the database engine is determined by getDatabaseService(env, isServerfull):
- Explicit Priority: If
DATABASE_SERVICE(orDB_SERVICE) is explicitly defined (D1,Turso,File, case-insensitive), it overrides all defaults; - Credential Inference: If
DATABASE_SERVICEis omitted, but validTURSO_DATABASE_URLandTURSO_AUTH_TOKENare present, the system automatically enables Turso mode; - Platform Default:
- Cloudflare Workers falls back to
D1; - Serverfull (Node.js/Bun/Docker) falls back to
File.
- Cloudflare Workers falls back to
6. Troubleshooting & Compatibility
Section titled “6. Troubleshooting & Compatibility”1. Turso Connection Timeout or SSL Error
Section titled “1. Turso Connection Timeout or SSL Error”- URL Protocol: DNS Worker automatically handles both
libsql://andhttps://protocols. If you encounter handshake issues on Workers, prefer specifyinghttps://.... - Expired Auth Token: Verify your token validity using
turso db tokens create. If you receive a401 Unauthorizederror, generate a new token.
2. Linux File Permission Denied (EACCES)
Section titled “2. Linux File Permission Denied (EACCES)”- When running as a non-root system user, ensure the data directory is writable:
Terminal window sudo mkdir -p /var/lib/dns-workersudo chown -R $USER:$USER /var/lib/dns-workersudo chmod 755 /var/lib/dns-worker
3. Inspecting Database Status
Section titled “3. Inspecting Database Status”Check current database status and disk usage from the command line:
dns-worker statusThe output displays the active database provider (File, Turso), database path, file size, and record counts.
