Skip to content

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 .gitignore in this project ignores .env, but double-check with git status before 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 live
  • IPV6_ENABLED — toggle IPv6 on/off
  • DISCORD_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.