Cloudflare DDNS Updater
Keeps Cloudflare DNS records pointed at the machine's current public IPv4 and/or IPv6 address.
The container reads:
- Environment variables from Docker, usually via
--env-file .env. - DNS update rules from
/home/node/app/configs/UpdaterConfig.jsoninside the container.
Quick Start
Pull the published image:
docker pull ghcr.io/yuzuzensai/cloudflare-ddns-updater:latest
Create .env from the example and set your Cloudflare API token:
cp .env.example .env
NODE_ENV=production
EXAMPLE_SITE_TOKEN=replace-with-cloudflare-api-token
Create configs/UpdaterConfig.json:
[
{
"token": "{ENV_TOKEN:EXAMPLE_SITE_TOKEN}",
"updateInterval": 60,
"zone": [
{
"id": "cloudflare-zone-id",
"type": "A",
"name": "example.com",
"content": "{CURRENT_IPv4}",
"ttl": 1,
"proxied": false
},
{
"id": "cloudflare-zone-id",
"type": "AAAA",
"name": "example.com",
"content": "{CURRENT_IPv6}",
"ttl": 1,
"proxied": false
}
]
}
]
Run the container:
docker run -d \
--name cloudflare-ddns-updater \
--restart unless-stopped \
--env-file .env \
-v "$(pwd)/configs:/home/node/app/configs" \
ghcr.io/yuzuzensai/cloudflare-ddns-updater:latest
View logs:
docker logs -f cloudflare-ddns-updater
Docker Compose
services:
cloudflare-ddns-updater:
image: ghcr.io/yuzuzensai/cloudflare-ddns-updater:latest
container_name: cloudflare-ddns-updater
restart: unless-stopped
env_file:
- .env
volumes:
- ./configs:/home/node/app/configs
docker compose up -d
Configuration
configs/UpdaterConfig.json is an array of Cloudflare account/token configurations.
Each top-level object:
| Field | Description |
|---|---|
token |
Cloudflare API token, or an environment reference like {ENV_TOKEN:EXAMPLE_SITE_TOKEN} |
updateInterval |
Update interval in seconds |
zone |
DNS records to manage |
Each zone entry:
| Field | Description |
|---|---|
id |
Cloudflare zone ID |
type |
DNS record type, usually A or AAAA |
name |
DNS record name, e.g. example.com or home.example.com |
content |
{CURRENT_IPv4} for an A record, {CURRENT_IPv6} for an AAAA record |
ttl |
Cloudflare TTL. Use 1 for automatic |
proxied |
Cloudflare proxy status, true or false |
Cloudflare Zone ID and API Token
Zone ID — In the Cloudflare dashboard, select the domain, open its overview page, and copy Zone ID from the API section of the right sidebar into zone[].id.
API token — In the dashboard, go to your profile icon → My Profile → API Tokens → Create Token. Use the built-in Edit zone DNS template (recommended) or a custom token with Zone > DNS > Edit and Zone > Zone > Read permissions. Either way, scope Zone Resources to Include → Specific zone → your domain, then create and copy the token — Cloudflare only shows it once. Don't use your Global API Key; the updater only needs a scoped token for the zones it manages.
Put the token in .env under any variable name you like, then reference that same name from UpdaterConfig.json:
HOME_SITE_TOKEN=your-cloudflare-api-token
"token": "{ENV_TOKEN:HOME_SITE_TOKEN}"
Avoid writing the literal token directly into UpdaterConfig.json — {ENV_TOKEN:...} keeps the secret in .env, which is gitignored.
Development
bun install
bun run dev # run with --watch
bun run check # typecheck + format + lint + test
Notes
- IPv4 is looked up via
https://api.ipify.org?format=json, IPv6 viahttps://api64.ipify.org/?format=json. - If
configs/UpdaterConfig.jsonis missing, the app creates one from the bundled example — edit it before real use.