2026-07-21 03:11:31 +07:00
# ☁️ Cloudflare DDNS Updater
2026-07-01 03:38:51 +07:00
2026-07-01 13:27:50 +07:00
Keeps Cloudflare DNS records pointed at the machine's current public IPv4 and/or IPv6 address.
2026-07-01 03:38:51 +07:00
The container reads:
- Environment variables from Docker, usually via `--env-file .env` .
- DNS update rules from `/home/node/app/configs/UpdaterConfig.json` inside the container.
## Quick Start
Pull the published image:
```sh
docker pull ghcr.io/yuzuzensai/cloudflare-ddns-updater:latest
```
2026-07-01 13:27:50 +07:00
Create `.env` from the example and set your Cloudflare API token:
2026-07-01 03:38:51 +07:00
```sh
cp .env.example .env
```
```env
NODE_ENV = production
EXAMPLE_SITE_TOKEN = replace-with-cloudflare-api-token
```
Create `configs/UpdaterConfig.json` :
```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:
```sh
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:
```sh
docker logs -f cloudflare-ddns-updater
```
## Docker Compose
```yaml
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
```
```sh
docker compose up -d
```
## Configuration
`configs/UpdaterConfig.json` is an array of Cloudflare account/token configurations.
2026-07-01 13:27:50 +07:00
Each top-level object:
2026-07-01 03:38:51 +07:00
2026-07-01 13:27:50 +07:00
| 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 |
2026-07-01 03:38:51 +07:00
2026-07-01 13:27:50 +07:00
Each `zone` entry:
2026-07-01 03:38:51 +07:00
2026-07-01 13:27:50 +07:00
| 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` |
2026-07-01 03:38:51 +07:00
2026-07-01 13:27:50 +07:00
## Cloudflare Zone ID and API Token
2026-07-01 03:38:51 +07:00
2026-07-01 13:27:50 +07:00
**Zone ID** — In the [Cloudflare dashboard ](https://dash.cloudflare.com/ ), select the domain, open its overview page, and copy `Zone ID` from the `API` section of the right sidebar into `zone[].id` .
2026-07-01 03:38:51 +07:00
2026-07-01 13:27:50 +07:00
**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.
2026-07-01 03:38:51 +07:00
2026-07-01 13:27:50 +07:00
Put the token in `.env` under any variable name you like, then reference that same name from `UpdaterConfig.json` :
2026-07-01 03:38:51 +07:00
```env
2026-07-01 13:27:50 +07:00
HOME_SITE_TOKEN = your-cloudflare-api-token
2026-07-01 03:38:51 +07:00
```
```json
"token" : "{ENV_TOKEN:HOME_SITE_TOKEN}"
```
2026-07-01 13:27:50 +07:00
Avoid writing the literal token directly into `UpdaterConfig.json` — `{ENV_TOKEN:...}` keeps the secret in `.env` , which is gitignored.
2026-07-01 03:38:51 +07:00
2026-07-01 13:27:50 +07:00
## Development
```sh
bun install
bun run dev # run with --watch
bun run check # typecheck + format + lint + test
2026-07-01 03:38:51 +07:00
```
## Notes
2026-07-01 13:27:50 +07:00
- IPv4 is looked up via `https://api.ipify.org?format=json` , IPv6 via `https://api64.ipify.org/?format=json` .
- If `configs/UpdaterConfig.json` is missing, the app creates one from the bundled example — edit it before real use.