DigitalOcean-based Dynamic DNS, with client/server architecture
There are plenty of scripts and small programs, like anaganisk/digitalocean-dynamic-dns-ip, which run entirely on the client. The problem there is that the client has to have a DigitalOcean API key with
write scope, which allows anyone with access to that client to make changes throughout your DigitalOcean account.
This project's architecture is more complex, but ensures that even a shared or compromised client can only change its own dynamic DNS record and can't interfere with records for other clients or anything else in your DigitalOcean account.
- client/server architecture protects your DigitalOcean API key from untrustworthy clients
- supports DynDns-style update API, for use with routers/devices with builtin DynDns support
- supports IPv4 and IPv6
You'll need two different domains, such as
aaaa.ddns.example.net, set up to point to the same server. One (
a.ddns.example.net) should have only an A record pointing to the server's IPv4 address; and the other (
aaaa.ddns.example.net) should have only an AAAA record pointing to the server's IPv6 address.
Server & Client (systemd)
Create a user and group for the service to use, and create a directory in
/etc for configuration:
# as root... useradd -r -U -s /sbin/nologin do-ddns mkdir /etc/do-ddns chown root:do-ddns /etc/do-ddns
# as root... # update the version and OS/architecture in the following release URL as desired. curl -L --silent https://github.com/cdzombak/do-ddns/releases/download/v0.0.1/do-ddns-0.0.1-linux_amd64.tar.gz | tar -C /usr/local/bin -xzv ./do-ddns-server chown do-ddns:do-ddns /usr/local/bin/do-ddns-server chmod +x /usr/local/bin/do-ddns-server curl -L --silent https://raw.githubusercontent.com/cdzombak/do-ddns/master/server/deployment/.env.sample > /etc/do-ddns/.env nano /etc/do-ddns/.env # customize as needed chown root:do-ddns /etc/do-ddns/.env curl -L --silent https://raw.githubusercontent.com/cdzombak/do-ddns/master/server/deployment/domains.json.sample > /etc/do-ddns/domains.json nano /etc/do-ddns/domains.json # customize as needed chown root:do-ddns /etc/do-ddns/domains.json # Install and start the server systemd unit: curl -L --silent https://raw.githubusercontent.com/cdzombak/do-ddns/master/server/deployment/do-ddns-server.service > /etc/systemd/system/do-ddns-server.service systemctl daemon-reload systemctl enable do-ddns-server systemctl start do-ddns-server # Test that the service is working: curl -i localhost:7001/ping # Configure nginx, or whatever frontend reverse proxy you're using: curl -L --silent https://raw.githubusercontent.com/cdzombak/do-ddns/master/server/deployment/nginx-ddns.conf > /etc/nginx/sites-available/ddns.example.net nano /etc/nginx/sites-available/ddns.example.net # customize as needed ln -s /etc/nginx/sites-available/ddns.example.net /etc/nginx/sites-enabled/ddns.example.net # Setup TLS as needed/desired. Depending on your nginx configuration, the following command may differ, though it'll work with the provided example nginx config file: certbot certonly --webroot --agree-tos --no-eff-email --email email@example.com -w /var/www/letsencrypt -d a.ddns.example.net -d aaaa.ddns.example.net systemctl reload nginx # Test that the frontend is serving: curl -i https://a.ddns.example.net/ping
# as root... # update the version and OS/architecture in the following release URL as desired. curl -L --silent https://github.com/cdzombak/do-ddns/releases/download/v0.0.1/do-ddns-0.0.1-linux_amd64.tar.gz | tar -C /usr/local/bin -xzv ./do-ddns-client chown do-ddns:do-ddns /usr/local/bin/do-ddns-client chmod +x /usr/local/bin/do-ddns-client curl -L --silent https://raw.githubusercontent.com/cdzombak/do-ddns/master/client/deployment/.env.sample > /etc/do-ddns/.env nano /etc/do-ddns/.env # customize as needed chown root:do-ddns /etc/do-ddns/.env # Install and start the client systemd unit: curl -L --silent https://raw.githubusercontent.com/cdzombak/do-ddns/master/client/deployment/do-ddns-client.service > /etc/systemd/system/do-ddns-client.service systemctl daemon-reload systemctl enable do-ddns-client systemctl start do-ddns-client
# update the version and OS/architecture in the following release URL as desired. curl -L --silent https://github.com/cdzombak/do-ddns/releases/download/v0.0.1/do-ddns-0.0.1-darwin_amd64.tar.gz | tar -C /usr/local/bin -xzv ./do-ddns-client chmod +x /usr/local/bin/do-ddns-client curl -L --silent https://raw.githubusercontent.com/cdzombak/do-ddns/master/client/deployment/org.dzombak.do-ddns-client.plist ~/Library/LaunchAgents/org.dzombak.do-ddns-client.plist sudo launchctl load -w ~/Library/LaunchAgents/org.dzombak.do-ddns-client.plist
DynDns Update API Support
The server also supports clients which use the DynDns update API, like routers. Configuration required on the client:
- Hostname: the domain to update (eg.
- Username: the domain to update (eg.
- Password: the secret for the selected domain
- Server: the server running
The DynDns API requires the client to pass its IP in the request. By default,
do-ddns-server ignores this and uses the request's remote address. To allow using the IP passed by the client (in the
myip query parameter), add
"allowClientIPChoice": true to a domain's configuration.
allowClientIPChoice is enabled, and the client's remote address as seen by the server is a different IP version from the
myip passed by the client, the server will use both these pieces of information to update the domain's A and AAAA records.
Note that the server does not allow updating multiple domains in one request, though the DynDns API does allow passing a comma-separated list of domains in the
do-ddns-server will return an
HTTP 400 Bad Request in this case.
Advanced Usage Notes
- Send the server process SIGUSR2 to reload its configuration file in-place.
- The domain configuration option
createMissingRecordsallows the server to create missing A/AAAA records for the domain as needed.
Chris Dzombak, dzombak.com
I wrote this partly as an exercise in Golang, and some bits of the code are based on other open-source projects and blog posts:
- DigitalOcean API code is adapted from anaganisk/digitalocean-dynamic-dns-ip
- The HTTP handler/error handling approach is adapted from http.Handler and Error Handling in Go by Matt Silverlock
Mozilla Public License, v. 2.0. See
LICENSE in the repository.