Configuration Reference¶
All configuration is done through environment variables in a .env file in the project root. Copy .env.sample to get started:
cp .env.sample .env
Then edit .env with your values.
All Environment Variables¶
Cloudflare¶
| Variable | Required | Default | Description |
|---|---|---|---|
CF_API_TOKEN |
Yes | — | Cloudflare API token with Zone:Zone:Read and Zone:DNS:Edit permissions. See Cloudflare Setup. |
Authentication¶
| Variable | Required | Default | Description |
|---|---|---|---|
ADMIN_EMAIL |
No | admin@localhost.local |
Email address used to log into the web dashboard |
ADMIN_PASSWORD |
No | ChangeMe! |
Password for the dashboard. Change this. Minimum 8 characters, maximum 128. |
SECRET_KEY |
Yes | your-secret-key-change-in-production |
Random string used to sign JWT session cookies. If this is guessable, session tokens can be forged. Generate with openssl rand -hex 32. |
Sync Behavior¶
| Variable | Required | Default | Description |
|---|---|---|---|
POLL_INTERVAL_SECONDS |
No | 300 |
How often (in seconds) the worker checks for IP changes. Must be between 60 and 7200. |
IPV6_ENABLED |
No | false |
Set to true to detect your IPv6 address and sync AAAA records. Set to false to only manage A records. |
Notifications¶
| Variable | Required | Default | Description |
|---|---|---|---|
DISCORD_WEBHOOK_URL |
No | (empty) | Discord webhook URL. When set, the worker sends alerts for IP changes and sync errors. Leave blank to disable. |
Timezone¶
| Variable | Required | Default | Description |
|---|---|---|---|
TZ |
No | America/Denver |
Timezone for timestamps in the audit log and application logs. Use IANA timezone format. |
Common timezone values:
America/New_York # US Eastern
America/Chicago # US Central
America/Denver # US Mountain
America/Los_Angeles # US Pacific
Europe/London # UK
Europe/Paris # Central Europe
Asia/Tokyo # Japan
Australia/Sydney # AEST
UTC # Universal
Full list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
Database (Advanced)¶
| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL |
No | sqlite:////data/ddns.db |
SQLite database file path. The default points to the Docker volume. Only change this for non-Docker deployments. |
Frontend (Docker / Remote Deployments)¶
| Variable | Required | Default | Description |
|---|---|---|---|
NEXT_PUBLIC_API_URL |
Situational | http://localhost:8081 |
The public URL of the API service. The browser uses this to make API calls. Must be set to your public API URL when deploying remotely. |
The .env File¶
A complete example .env:
# ── CLOUDFLARE ──────────────────────────────────────────────────────────────
CF_API_TOKEN=your_cloudflare_api_token_here
# ── AUTHENTICATION ───────────────────────────────────────────────────────────
ADMIN_EMAIL=you@example.com
ADMIN_PASSWORD=a-strong-password-here
# Generate with: openssl rand -hex 32
SECRET_KEY=a64characterhexstringgoeshere1234567890abcdef1234567890abcdef12
# ── SYNC ─────────────────────────────────────────────────────────────────────
POLL_INTERVAL_SECONDS=300
IPV6_ENABLED=false
# ── NOTIFICATIONS ─────────────────────────────────────────────────────────────
DISCORD_WEBHOOK_URL=
# ── TIMEZONE ─────────────────────────────────────────────────────────────────
TZ=America/New_York
Security Notes¶
SECRET_KEY¶
The SECRET_KEY signs JWT session tokens. If this is weak or the default value, an attacker who knows the key can forge valid session cookies and log in as you without knowing the password.
Generate a proper key:
openssl rand -hex 32
Never use the default your-secret-key-change-in-production value in any environment where the app is accessible from the internet.
ADMIN_PASSWORD¶
Must be between 8 and 128 characters. Use a password manager to generate something strong. The password is stored as a bcrypt hash in the database — it's never stored in plaintext.
CF_API_TOKEN¶
- Keep this out of version control. The
.gitignorein this project ignores.env, but double-check withgit statusbefore committing. - Scope the token to only the zones Dreadnought manages.
- Rotate it periodically. See Cloudflare Setup.
DISCORD_WEBHOOK_URL¶
Discord webhook URLs are not secret (they're just URLs), but treat them as sensitive: anyone with the URL can post to your channel. Keep them out of public repositories.
NEXT_PUBLIC_API_URL — Explained¶
This variable deserves special attention because it's a common source of confusion.
What it is¶
NEXT_PUBLIC_API_URL is a Next.js "public" environment variable — it gets baked into the browser-side JavaScript bundle at build time. It tells the browser where to find the API.
When to change it¶
| Scenario | What to set |
|---|---|
| Running locally on the same machine | http://localhost:8081 (default — no change needed) |
| Accessing from another device on your LAN | http://your-server-ip:8081 |
| Running behind a reverse proxy with a domain | https://ddns-api.yourdomain.com |
| Coolify or similar PaaS deployment | https://ddns-api.yourdomain.com |
How to change it in docker-compose.yml¶
Edit the web service's environment section in docker-compose.yml:
web:
environment:
- NEXT_PUBLIC_API_URL=https://ddns-api.yourdomain.com
- NODE_ENV=production
Or in a .env file (if you reference it in compose):
NEXT_PUBLIC_API_URL=https://ddns-api.yourdomain.com
What happens if it's wrong¶
If NEXT_PUBLIC_API_URL points to a URL the browser can't reach, the dashboard will load but all API calls will fail. The login page will appear to hang or show a network error. The API itself (and the worker) will still function correctly — they communicate internally and don't use this variable.
Changing Settings at Runtime¶
Some settings can be changed in the app's Settings page without editing .env:
POLL_INTERVAL_SECONDS— adjust the sync interval liveIPV6_ENABLED— toggle IPv6 on/offDISCORD_WEBHOOK_URL— update or clear the webhook
Settings changed in the UI are stored in the database and take effect on the next worker cycle. The .env values set the initial defaults; database values take precedence once they've been set.
Generating a SECRET_KEY¶
Linux / macOS:
openssl rand -hex 32
Python (cross-platform):
python3 -c "import secrets; print(secrets.token_hex(32))"
Windows PowerShell:
-join ((1..32) | ForEach-Object { '{0:x2}' -f (Get-Random -Max 256) })
Or use any password manager's random string generator set to 64+ characters of hex/alphanumeric.