Dynamic DNS in a Container: Deploying ddclient with Docker and Cloudflare
Dynamic DNS in a Container: Deploying ddclient with Docker and Cloudflare
The modern homelab often faces a critical networking challenge: a dynamic IP address. When your Internet Service Provider (ISP) changes your public IP address, which can happen without warning, any service you host, like a VPN, a website, or a game server, instantly becomes inaccessible. The solution is Dynamic DNS (DDNS).
This guide details an easily maintainable DDNS setup using the powerful open-source client ddclient, containerized with Docker, and integrated with Cloudflare to manage your DNS records.
1. Why Docker and Cloudflare?
The Power of Containerization (Docker)
Running ddclient within a Docker container offers several advantages over a native system installation (such as a VM or bare-metal):
- Isolation: The client runs in a self-contained environment, preventing configuration conflicts or library dependencies from affecting the host operating system.
- Portability: You can move the entire setup (the configuration file and the
docker-compose.yml) between different hosts (e.g., from a Raspberry Pi to a dedicated server) in minutes. - Reliability: Using maintained images, like the one from LinuxServer.io, ensures you are running a stable, up-to-date version of
ddclientthat supports the latest Cloudflare API requirements. - Persistence: By using a volume mount, the critical configuration and cache files remain intact even if the container is rebuilt or replaced.
The Advantage of Cloudflare
Cloudflare provides a ton of services, often for free, complete with a robust and well-documented API. Using Cloudflare as your DDNS provider means you benefit from their global network, performance optimizations, and security features like DDoS protection and optional proxying.
2. Setting Up Security: The Cloudflare API Token
We will create a scoped API Token with minimal permissions. This token will only be able to modify DNS records for the specific domain (Zone) you define. Another option is using your Global API key, but I wouldn't recommend it as it has full control over your entire Cloudflare account.
- Navigate to your Cloudflare dashboard and go to My Profile > API Tokens.
- Click Create Token.
- Select the "Create Custom Token" option.
- Token Name: Give it a descriptive name, e.g.
ddclient-ddns. - Permissions: Add the following two permissions:
- Zone | DNS | Edit
- Zone | Zone | Read
- Zone Resources: Set this to Include | Specific Zone and select your domain (e.g.
cjett.net). - Click Continue to summary and then Create Token.
Cloudflare will only display the token once. Copy it immediately and stash it somewhere safe. This token will serve as the "password" in your ddclient configuration.
3. Configuring ddclient.conf
The heart of the setup is the ddclient.conf file, which dictates how the client finds your current IP and how it authenticates and communicates with Cloudflare.
Create a directory on your host (e.g., /opt/ddclient/config) and place the following file named ddclient.conf inside it.
# Global configuration settings
daemon=300 # Check for new IP every 300 seconds (5 minutes)
syslog=yes # Log messages to syslog
ssl=yes # Use SSL/TLS for secure communication
use=web, web=ipify-ipv4 # Use the ipify service to determine external IPv4 address
# Cloudflare specific configuration
protocol=cloudflare, \
zone=cjett.net, \
ttl=1, \
login=token, \
password='YOUR_API_TOKEN_HERE' \
cjett.net, \
blog.cjett.net
Key Parameter Breakdown:
daemon=300: Sets the refresh interval to 5 minutes. Use a higher value if you want to be less aggressive.use=web, web=ipify-ipv4: This tellsddclientto query an external web service (ipify) to discover your public IP address.protocol=cloudflare: Use the Cloudflare API.zone: The domain to update records in.login=token: Instructs the client to use API token authentication (bearer token). You can also just comment out this line.password='YOUR_API_TOKEN_HERE': Paste the API Token you generated in Section 2. You may need to wrap this in single quotes (').*.cjett.net: A comma-separated list of the Fully Qualified Domain Names (FQDNs) you want to update.
4. Containerizing with Docker Compose
Using Docker Compose simplifies the deployment, ensures proper persistent storage, and makes the entire setup easy to manage. We will use the widely trusted lscr.io/linuxserver/ddclient image.
version: "4.0"
services:
ddclient:
image: lscr.io/linuxserver/ddclient:4.0.0
container_name: ddclient
network_mode: host
environment:
# Optional: set User/Group IDs for volume permissions
- PUID=1000
- PGID=1000
- TZ=America/New_York
volumes:
- /opt/ddclient/config:/config
restart: unless-stopped
Key Compose Parameter Breakdown:
network_mode: host: This configures the container to share the host's network stack, ensuring that whenddclientchecks its IP, it sees the actual public IP address of your network, not the internal IP of the Docker bridge.volumes: - /opt/ddclient/config:/config: This maps your local configuration directory (/opt/ddclient/config) containing theddclient.conffile to the location where the container expects it (/config).
Deployment
With the ddclient.conf and docker-compose.yml files saved, deploy the container with a single command:
docker compose up -d
5. Verification and Maintenance
Once deployed, you need to verify that ddclient is communicating correctly with Cloudflare.
Checking the Logs
The container will start the ddclient daemon, which logs its activities. Check the logs for a successful update message:
docker logs -f ddclient
You should see output similar to:
SUCCESS: [cloudflare][cjett.net]> IPv4 address set to [your.public.ip]
Final Check
Verify the change directly in your Cloudflare DNS dashboard. The A record for your configured hostnames should now point to your current public IP address. With the daemon=300 setting, every 5 minutes ddclient will check if your public IP has changed, and if necessary, push the update to Cloudflare.
Troubleshooting
If you encounter errors (e.g., Invalid request headers, Invalid format for X-Auth-Key header), double-check the API token permissions and ensure the password value in ddclient.conf is wrapped in single quotes (').
To accelerate the troubleshooting process, add min-error-interval=10s to the ddclient.conf file. In the event that the update to Cloudflare fails, adding this to your configuration will force it to retry again after 10 seconds (instead of waiting for the value that daemon is set to).