Dynamic DNS (with DuckDNS)
Dynamic DNS will let us access our PiServer over the internet even though our home IP address might be changing, as is common with consumer ISPs.
An easy way to find out our external IP address (i.e. the one that our router has) is
While any Dynamic DNS provider can be used, we will use DuckDNS as an example because it is free and easy-to-use. The steps outlined in this chapter can be adapted for any other Dynamic DNS provider.
See alternative: Tor.
- The file containing the secret token is secured.
- The systemd application has minimal privileges.
DNS and Custom Domains
A custom domain is not necessary, because our Dynamic DNS provider will (usually?) give us one. For example,
However, if we have one then we can add a
CNAME record for our nicer domain, e.g.
piserver.example.com to point to the uglier domain.
We can further chain the
CNAME records, for example, we might point
DuckDNS uses a secret token as part of the URL query string. To avoid insecurely placing this as a parameter to curl, we will configure our command to use a curl config file. We will create this at
url = "https://www.duckdns.org/update?domains=<DOMAIN>&token=<TOKEN>&ip=" # Only log errors silent show-error # Do not redirect max-redirs = 0 # Don't spend longer than 10 seconds on each try max-time = 10 # Don't spend longer than 30 seconds in total retry-max-time = 30 # Retry up to 5 times with exponential backoff retry = 5 # Retry even when connection was refused retry-connrefused # Security, use tlsv1.2+ (tlsv1.3 is not supported by server) tlsv1.2 # Require OCSP stapling (not supported by server) # cert-status # Use TCP Fast Open for extra performance tcp-fastopen
<TOKEN> placeholders (or, indeed, the entire URL).
This file is secure because
/var/lib/private acts as a boundary, allowing only
We are overloading
duckdns.confto include both the curl configuration and the secret token. It could be split into two files, and
--configgiven twice to curl.
Service & Auto-update Script
The systemd script at
[Unit] Description=Update the dynamic IP address on DuckDNS After=network-online.target Wants=network-online.target # OnFailure=notify-email@%N.service [Service] Type=oneshot DynamicUser=yes StateDirectory=duckdns ExecStart=/usr/bin/curl --config /var/lib/duckdns/duckdns.conf SyslogIdentifier=duckdns Nice=19 # Additional Security: #* PrivateTmp=yes #* RemoveIPC=yes ProtectHome=yes PrivateDevices=yes PrivateUsers=yes PrivateMounts=yes PrivateTmp=yes # We need the internet # PrivateNetwork=yes ProtectSystem=Strict ProtectHome=yes ProtectKernelTunables=yes ProtectKernelModules=yes ProtectControlGroups=yes RestrictNamespaces=yes RemoveIPC=yes NoNewPrivileges=yes RestrictAddressFamilies= MemoryDenyWriteExecute=yes SystemCallArchitectures=native #* RemoveIPC=yes RestrictRealtime=yes RestrictAddressFamilies= SystemCallFilter=@system-service CapabilityBoundingSet= AmbientCapabilities=
- This can be executed with
sudo systemctl start duckdns.
- This can be monitored with
sudo systemctl status duckdnsor
sudo journalctl -u duckdns.
The above is a systemd service that simply runs the command and exits. We can create a systemd timer to run this oneshot command periodically at
[Unit] Description=Run duckdns.service every minute [Timer] OnBootSec=30 OnUnitActiveSec=1min [Install] WantedBy=timers.target
We'll start the timer 30 seconds after boot to let the system settle, and thereafter every minute after the last execution.
- This can be enabled with
sudo systemctl enable --now duckdns.timer
Port-Forwarding & Testing
- We can test the DNS records using
- We will almost certainly need to port-forward incoming connections to the PiServer on our router, for example port-forward port 24 on the router to port 22 on the PiServer to allow us to SSH-in from the internet.
- We may not be able to SSH in to our router's public IP address, so we could try using a mobile connection instead (e.g. our phone with a WiFi hotspot).
- [ ] What is the cause of this problem?
If we have set up monitoring on our PiServer, we can un-comment
OnFailure in the above service file. This will notify us via email if the service fails.
We can test this by temporarily editing
duckdns.conf with an invalid URL.
Add the following lines to the backup script:
/etc/systemd/system/duckdns.service \ /etc/systemd/system/duckdns.timer \ /etc/systemd/system/timers.target.wants/duckdns.timer \ /var/lib/private/duckdns/duckdns.conf \
No special steps are required.
We looked at why a Dynamic DNS service is useful for us, and created a systemd service and timer to automatically update our Dynamic DNS service provider with our PiServer's IP address.