101bedda97b0c8e05a243799ee5bac4d49a45b31
ddns-updater
A small Go daemon that keeps Cloudflare A records in sync with your current public IPv4 address.
It reads a YAML config, checks your IP periodically, compares it to existing DNS records, and only updates when needed.
Features
- Uses Cloudflare API token (modern auth)
- Supports multiple subdomains in one zone
- IPv4 only (A records)
- User-defined check interval (minutes)
- Retries on failure, then logs and skips
- Structured JSON logging to file
Requirements
- Go 1.21+ (tested with 1.23)
- A Cloudflare account
- API token with:
- Zone:DNS:Edit
- Zone:Zone:Read
- Existing zone and A records for your subdomains
Installation
# 1. Create project directory
mkdir ddns-updater
cd ddns-updater
# 2. Initialize module
go mod init github.com/yourname/ddns-updater
# 3. Add files
# - main.go
# - config.yaml
# - (this README.md)
# 4. Fetch dependencies
go mod tidy
# 5. Build binary (current platform)
go build -o ddns-updater
# 6. Build for Linux (LXC, etc.)
GOOS=linux GOARCH=amd64 go build -o ddns-updater-linux
Copy the resulting binary and config.yaml onto your target machine or LXC container, e.g. /opt/ddns-updater.
Configuration
Create config.yaml in the same directory as the binary:
check_interval: 5 # minutes (e.g. 5, 15, 30)
cloudflare:
api_token: "YOUR_CF_API_TOKEN"
zone_id: "YOUR_ZONE_ID"
subdomains:
- name: "lc"
proxied: false
- name: "git"
proxied: false
- name: "mempool"
proxied: false
logging:
file: "ddns-updater.log"
level: "info" # debug, info, warn, error
retry:
max_attempts: 3
delay_seconds: 5
webhook:
enabled: false
url: ""
check_interval: how often to check your current IP (in minutes).subdomains: just the left part of the name (e.g.gitforgit.example.com).proxied:truefor orange-cloud (proxied),falsefor DNS only.logging.file: log file path, relative to the working directory.retry: per-subdomain retry behavior when the Cloudflare API or network fails temporarily.
Usage
Direct run
From the directory containing the binary and config.yaml:
./ddns-updater
The process will:
- Load
config.yaml. - Detect current public IPv4 using external services.
- For each subdomain:
- Fetch its current A record from Cloudflare.
- If the IP differs, update the record.
- Sleep for
check_intervalminutes and repeat. - Log events to
ddns-updater.log.
Run in background (simple)
nohup ./ddns-updater >/dev/null 2>&1 &
Example systemd service (on Linux/LXC)
Create /etc/systemd/system/ddns-updater.service:
[Unit]
Description=Cloudflare DDNS Updater
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/ddns-updater
ExecStart=/opt/ddns-updater/ddns-updater
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
Then:
sudo systemctl daemon-reload
sudo systemctl enable ddns-updater
sudo systemctl start ddns-updater
sudo systemctl status ddns-updater
Logs will go to ddns-updater.log in /opt/ddns-updater plus systemd’s journal.
Updating
To update the binary:
git pull # if you put it in a repo
go build -o ddns-updater
sudo systemctl restart ddns-updater
Languages
Go
71.4%
Makefile
25.7%
Dockerfile
2.9%