#Cloudflare的动态DNS客户端
一个小型工具,用于使用当前检测到的指定网络接口的地址更新Cloudflare DNS上的IPv6地址。
##特征
- Intellegent IPv6 address selection
- Support for multiple domains
- Systemd service and timer files for automation
- Can be run as a Docker containern
- Configuration via command line arguments, config file or environment variables
- Support for multiple hosts in the same domain (experimental)
The rest of this section is the output of cloudflare-dynamic-dns --help
.
Selects an IPv6 address from the specified network interface and updates AAAA records at Cloudflare for the configured domains. Required configuration options -------------------------------------------------------------------------------- --iface: network interface name to look up for an IPv6 address --domains: one or more domain names to assign the IPv6 address to --token: Cloudflare API token with edit access rights to the DNS zone IPv6 address selection -------------------------------------------------------------------------------- When multiple IPv6 addresses are found on the interface, the following rules are used to select the one to use: 1. Only global unicast addresses (GUA) and unique local addresses (ULA) are considered. 2. GUA addresses are preferred over ULA addresses. 3. Unique EUI-64 addresses are preferred over randomly generated addresses. 4. If priority subnets are specified, addresses from the subnet with the highest priority are selected. The priority is determined by the order of subnets specified on the command line or in the config file. Daemon mode -------------------------------------------------------------------------------- By default, the program runs once and exits. This mode of operation can be changed by setting the --run-every flag to a duration greater than 1m. In this case, the program will run repeatedly, waiting the duration between runs. It will stop if killed or if failed. State file -------------------------------------------------------------------------------- Setting --state-file makes the program to retain the previously used IPv6 address between runs to avoid unnecessary calls to the Cloudflare API. The value is used as the state file path. When used with an empty value, the state file is named after the interface name and the domains, and is stored either in the current directory or in the directory specified by the STATE_DIRECTORY environment variable. The STATE_DIRECTORY environment variable is automatically set by systemd. It can be set manually when running the program outside of systemd. Multihost mode (EXPERIMENTAL) -------------------------------------------------------------------------------- In this mode, it is possible to assign multiple IPv6 addresses to a single or multiple domains. For correct operation, this mode must be enabled on all hosts participating in the same domain and different host-ids must be specified for each host (see --host-id option). This mode is enabled by passing --multihost flag. In the multihost mode, the program will manage only the DNS records that have the same host-id as the one specified on the command line or in the config file. If an existing record has no host-id but has the same address as the target one, it will be claimed by this host via setting the corresponding host-id. Any other records will be ignored. This allows multiple hosts to share the same domain without interfering with each other. The host-id is stored in the Cloudflare DNS comments field (see https://developers.cloudflare.com/dns/manage-dns-records/reference/record-attributes/). Persistent configuration -------------------------------------------------------------------------------- The program can be configured using a config file. The default location is $HOME/.cloudflare-dynamic-dns.yaml. The config file location can be overridden using the --config flag. The config file format is YAML. The following options are supported (with example values): iface: eth0 token: cloudflare-api-token domains: - example.com - "*.example.com" # --- optional fields --- log-level: info priority-subnets: - 2001:db8::/32 - 2001:db8:1::/48 ttl: 180 run-every: 10m state-file: /tmp/cfddns-eth0.state multihost: true host-id: homelab-node-1 Environment variables -------------------------------------------------------------------------------- The configuration options can be specified as environment variables. To make an environment variable name, prefix a flag name with CFDDNS_, replace dashes with underscores, and convert to uppercase. List values are specified as a single string containing elements separated by spaces. For example: CFDDNS_CONFIG=/path/to/config.yaml CFDDNS_IFACE=eth0 CFDDNS_TOKEN=cloudflare-api-token CFDDNS_DOMAINS='example.com *.example.com' CFDDNS_LOG_LEVEL=info CFDDNS_PRIORITY_SUBNETS='2001:db8::/32 2001:db8:1::/48' CFDDNS_TTL=180 CFDDNS_RUN_EVERY=10m CFDDNS_STATE_FILE=/tmp/cfddns-eth0.state CFDDNS_MULTIHOST=true CFDDNS_HOST_ID=homelab-node-1 Usage: cloudflare-dynamic-dns [flags] Flags: --config string config file (default is $HOME/.cloudflare-dynamic-dns.yaml) --domains strings Domain names to assign the IPv6 address to. -h, --help help for cloudflare-dynamic-dns --host-id string Unique host identifier. Must be specified in multihost mode. Must be a valid DNS label. It is stored in the Cloudflare DNS comments field in the format: "host-id (managed by cloudflare-dynamic-dns)" --iface string Network interface to look up for a IPv6 address. --log-level string Sets logging level: trace, debug, info, warning, error, fatal, panic. (default "info") --multihost Enable multihost mode. In this mode it is possible to assign multiple IPv6 addresses to a single domain. For correct operation, this mode must be enabled on all participating hosts and different host-ids must be specified for each host (see --host-id option). --priority-subnets strings IPv6 subnets to prefer over others. If multiple IPv6 addresses are found on the interface, the one from the subnet with the highest priority is used. --run-every string Re-run the program every N duration until it's killed. The format is described at https://pkg.go.dev/time#ParseDuration. The minimum duration is 1m. Examples: 4h30m15s, 5m. --state-file string Enables usage of a state file. In this mode, previously used ipv6 address is preserved between runs to avoid unnecessary calls to CloudFlare API. Automatically selects where to store the state file if no value is specified. See the State file section in usage. --token string Cloudflare API token with DNS edit access rights. --ttl int Time to live, in seconds, of the DNS record. Must be between 60 and 86400, or 1 for 'automatic'. (default 1) -v, --version version for cloudflare-dynamic-dns
There are two packages in AUR ( 1, 2 ), that can be used on Arch-based distros:
yay -S cloudflare-dynamic-dns
# OR
yay -S cloudflare-dynamic-dns-bin
See the container registry page for details.
docker pull ghcr.io/zebradil/cloudflare-dynamic-dns:latest
See the latest release page for the full list of packages.
Download the archive for your OS from the releases page.
Or get the source code and build the binary:
git clone https://github.com/Zebradil/cloudflare-dynamic-dns.git
# OR
curl -sL https://github.com/Zebradil/cloudflare-dynamic-dns/archive/refs/heads/master.tar.gz | tar xz
cd cloudflare-dynamic-dns-master
go build -o cloudflare-dynamic-dns main.go
Now you can run cloudflare-dynamic-dns
manually (see Usage section).
If you want to do some automation with systemd, cloudflare-dynamic-dns
has to be installed system-wide
(it is possible to run systemd timer and service without root privileges, but I do not provide ready-to-use configuration for this yet):
sudo install -Dm755 cloudflare-dynamic-dns -t /usr/bin
sudo install -Dm644 systemd/* -t /usr/lib/systemd/system
sudo install -m700 -d /etc/cloudflare-dynamic-dns/config.d
- Follow the steps from the Installation section.
- Run
./cloudflare-dynamic-dns --domains 'example.com,*.example.com' --iface eth0 --token cloudflare-api-token
- NOTE: instead of compiling
cloudflare-dynamic-dns
binary, it can be replaced withgo run main.go
in the command above.
- NOTE: instead of compiling
Instead of specifying command line arguments, it is possible to create ~/.cloudflare-dynamic-dns.yaml
with the following structure:
iface: eth0
token: cloudflare-api-token
domains:
- example.com
- "*.example.com"
And then run ./cloudflare-dynamic-dns
(or go run main.go
) without arguments.
Or put the configuration in any place and specify it with --config
flag:
./cloudflare-dynamic-dns --config /any/place/config.yaml
It is possible to run cloudflare-dynamic-dns
periodically via systemd.
This requires privileged access to the system.
Make sure that required systemd files are installed (see Installation section for details).
# 1. Create configuration file `/etc/cloudflare-dynamic-dns/config.d/<name>.yaml`
# For example (I use "example.com" as <name>, replace the values according to your needs):
sudo tee -a /etc/cloudflare-dynamic-dns/config.d/example.com.yaml <<EOF
iface: eth0
token: cloudflare-api-token
domains:
- example.com
- "*.example.com"
EOF
# 3. Enable systemd timer
sudo systemctl enable --now cloudflare-dynamic-dns@example.com.timer
This way (via running multiple timers) you can use multiple configurations at the same time.
By default, a timer is triggered one minute after boot and then every 5 minutes. It is not configurable currently.
To avoid unnecessary requests to Cloudflare API state files are used.
They're created in /var/lib/cloudflare-dynamic-dns/
and named using configuration variables in corresponding config files (iface
and md5 hash of domains
).
A state file contains IPv6 address which was set in a Cloudflare DNS AAAA record during the last successful run.
If the current IPv6 address is the same as the one in the state file, no additional API requests are done.
Builds and releases are done with goreleaser.
Use the following Taskfile tasks to build the application:
# Build with go for the current platform
go build -o cloudflare-dynamic-dns main.go
# Build with GoReleaser for all configured platforms
task build
# Use Docker
docker build -t cloudflare-dynamic-dns -f dev.Dockerfile .
Do not change .goreleaser.yml
manually, do changes in .goreleaser.ytt.yml
and run
task misc:build:goreleaser-config
instead (requires ytt
installed).
The usage section is generated by the update_readme script.
For convenience, task docs:update-readme
can be used to run it.
This project is not affiliated with Cloudflare.