Not a Cron Comparison Link to heading

Cron may still have its place in Linux administration, but I won’t be weighing in on that. What I’ve found from my junior administrators is a willingness to utilize systemd, but they find a lot of information overwhelming. Below is a very simple guide for reliably running a script at a requested inverval.

Overview Link to heading

Systemd needs 2 files in order for this to work - a .service file that tells the server what to do, and a .timer file that tells the server when to do it. These need to have the same name - for example: certbot-renewal.service and certbot-renewal.timer. This guide assumes you want the scripts ran as the root user. Both .service and .timer files should be placed in /etc/systemd/system/.

Service Files Link to heading

See below for a simple example that I tend to utilize as a scaffolding file -

[Unit]
Description=Run Certbot Renewal with Standalone Web Server Mode
After=nginx.service

[Service]
Type=oneshot
ExecStartPre=/bin/systemctl stop nginx
ExecStart=/usr/bin/certbot renew --quiet --standalone
ExecStartPost=/bin/systemctl start nginx

[Install]
WantedBy=multi-user.target

I like to use the above as an example because it tiptoes into the power of systemd service files by allowing us to set actions before and after the main script runs. This example first stops the nginx web server, runs certbot on port 80 to renew a certifcate, and then starts nginx after its done.

Note that we use absolute paths in the scripts, we aren’t simply calling certbot we’re calling /usr/bin/certbot

Now that we have a series of actions that we want to take periodically, we now tell systemd when to start this service.

If you want to test or run these steps to validate your .service file, run systemd start certbot-renewal.service. This starts the service in the same manner the .timer file would, and in this case the service is of type=oneshot so it just runs the script exits. And thanks to systemd we get automatic logging, more on that later.

Timer Files Link to heading

Here is the corresponding .timer file for the certbot renewal service above -

[Unit]
Description=Run Certbot Renewal every week

[Timer]
OnCalendar=weekly
Persistent=true

[Install]
WantedBy=timers.target

By default, weekly means Monday morning at Midnight, and this can be observed by running

sytemd-analyze calendar weekly and you can get a view of all your timers (and their next run) with systemctl list-timers --all

You can also override the time/date if you want, below is a line that would run the .service at 4AM EST, every first of the month OnCalendar=*-*-01 04:00:00 America/New_York

and here is every day at 4AM EST -

OnCalendar=*-*-* 04:00:00 America/New_York

After you have a .timer file, all you need to do is run systemctl enable --now certbot-renewal.timer

  • --now makes sure the .timer is also started. Otherwise you’d have to run systemctl start certbot-renewal.timer as well.

Free Logging Link to heading

You wrote a .service file and you want to follow its log file live for errors -

journalctl -u certbot-renewal.service -f

You need to verify its been successful or not by checking its top 50 lines in the logfile -

journalctl -u certbot-renewal.service -n 50

Its been a few days/weeks and the timer should have ran a few times, but you want to spot check it -

systemctl status certbot-renewal.timer

Wrapping Up Link to heading

Eagle-eyed readers already familiar with systemd will notice that I made an “error”. The .service and .timer files don’t actually need the same name, but that is the configuration by default and I find that its easier to teach when we assume that to be true.

Anyway, hopefully this quick guide will help someone out there get started with using systemd to schedule tasks. Its incredibly powerful, but in my experience, this simple example goes a long way.