Running DuckDNS with a systemd timer

Lately I’ve been learning how to administer services that I want to run for fun. Some of these services don’t make sense for me to run outside of my network (i.e., on a VPS somewhere) but I still might want access to them if I’m ever away from my home network. A good example of this would be my IRC bouncer that I installed on my Raspberry Pi Zero W.

Since I don’t have a static IP for my home network (and I don’t want to ask for one from my ISP), I decided to go with DuckDNS as my dynamic DNS service. DuckDNS allows you to set a domain name like blah.duckdns.org and as long as you periodically make an HTTP request from your network to one of duckdns.org‘s endpoints, DuckDNS will automatically update blah.duckdns.org to point at your (potentially changing) home IP address.

The usual instructions for DuckDNS show you how to get started quickly by setting up a cronjob to make this HTTP request. Let’s go against the grain and get some more experience with systemd.

To get started, go ahead and create a domain at duckdns.org. Leave the instructions open for what the HTTP request is supposed to be.

Create a DuckDNS user

There’s no reason this script needs to run as your user or even worse, as root.

$ sudo groupadd duckdns
$ sudo useradd duckdns -g duckdns -m 

The above commands create the duckdns group and a user named duckdns. It adds the duckdns user to the duckdns group (-g flag) and creates a home directory for the duckdns user (-m).

Save the DuckDNS curl one-liner

DuckDNS shows you a cool one-liner for making the HTTP request when you create your DuckDNS domain. It should look something like this:

echo url="https://www.duckdns.org/update?domains=YOUR_DOMAIN&token=YOUR_TOKEN&ip=" | curl -k -o ~/duck.log -K -

Note that I’ve changed the output file in the curl command from ~/duckdns/duck.log to just ~/duck.log. If you don’t do this, you’ll need to create this folder structure for the script to work: /home/duckdns/duckdns.

Go ahead and save that one-liner to /home/duckdns/duckdns.sh.

Make duckdns the owner of that file with:

$ sudo chown duckdns:duckdns /home/duckdns/duckdns.sh
$ sudo chmod 700 /home/duckdns/duckdns.sh

Now let’s go ahead and create the actual systemd unit and timer.

Make a systemd unit

duckdns.service
[Unit]
Description=DuckDNS heartbeat
After=network-online.target
Wants=network-online.target

[Service]
User=duckdns
Group=duckdns
Type=oneshot
ExecStart=/bin/bash /home/duckdns/duckdns.sh
ProtectSystem=yes
NoNewPrivileges=yes
PrivateTmp=yes

[Install]
WantedBy=multi-user.target

Some of these options may admittedly be overkill, but let’s review some of the essentials:

  • After=network-online.target and Wants=network-online.target: since our service requires network connectivity to work, we require there to be a network connection before it runs.
  • User=duckdns and Group=duckdns: The process should be ran as duckdns.
  • Type=oneshot: This means that systemd will consider the unit “active” once it exits successfully.
  • WantedBy=multi-user.target: Once the system has reached a level where multiple users can login, we want this unit activated.

Make a systemd timer

duckdns.timer
[Unit]
Description=Timer for DuckDNS unit

[Timer]
OnCalendar=*:0/5

[Install]
WantedBy=timers.target

This one is a little bit simpler. The OnCalendar line is set to run the unit every five minutes.

Activate the timer

$ sudo cp duckdns.timer /lib/systemd/system/
$ sudo cp duckdns.service /lib/systemd/system/
$ sudo systemctl enable duckdns.timer

Confirm that it works

The service runs every five minutes, so you can sanity check that it’s scheduled to run and that it has ran with:

$ sudo systemctl list-timers --all
NEXT                         LEFT          LAST                         PASSED       UNIT                         ACTIVATES
Mon 2020-09-07 17:55:00 BST  2min 56s left Mon 2020-09-07 17:50:07 BST  1min 56s ago duckdns.timer                duckdns.service

Furthermore, you can also check the modified-time on /home/duckdns/duck.log: (the minute timestamp should be a multiple of 5)

$ ls -lh /home/duckdns/duck.log
-rw-r--r-- 1 duckdns duckdns 2 Sep  7 17:50 /home/duckdns/duck.log

And finally, you can check to make sure /home/duckdns/duck.log has “OK” logged (this indicates the script ran successfully):

$ cat /home/duckdns/duck.log
OK

You should now be able to reach your home network with your DuckDNS domain name!

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *