Timers are systemd unit files (files end in .timer) that control systemd service units (.service). For each timer file, a matching unit file must exist describing the unit to activate when the timer elapses. This post covers how to use systemd timers as an alternative to the cron. For more information refer to the man page systemd.timer(5)

Type of Timers

Timers are systemd unit files that end in .timer. They include a [Timer] section which defines when and how the timer activates.

  • Realtime timers: activate on a calendar event, the same way that cron jobs do. They are defined with OnCalendar=
  • Monotonic timers: relative to different starting point. They are defined with OnActiveSec=, OnBootSec=, OnStartupSec=, OnUnitActiveSec=, OnUnitInactiveSec=. For example, a timer which starts 5 minutes after boot.

Timer units

For each .timer file, a matching .service file must exist. For example for a foobar.timer timer a foobar.service should exist. The .timer file activates and controls the .service file. The .service doesn't require an [Install] section because the timer units are enabled.

It is possible to activate a unit with different name using the Unit= option in the [Timer] section.

systemd timers as a cron alternative

Timers work directly with services units. So we have to create the service unit in the /etc/systemd/system/ directory. Keep in mind that modifications done by system administrators go into /etc/systemd/system/. For example, create the file /etc/systemd/system/date.service:

[Unit]
Description=Prints date into /tmp/date file

[Service]
Type=oneshot
ExecStart=/usr/bin/bash -c '/usr/bin/date >> /tmp/date'
User=jdoe

Now we have to define in the same directory (/etc/systemd/system) the timer:

[Unit]
Description=Daily prints of date into /tmp/date file

[Timer]
OnCalendar=*-*-* 01:05:00
Persistent=true

[Install]
WantedBy=timers.target

Then run:

$ sudo systemctl daemon-reload

To use the timer unit enable and start it, like any other unit but using the .timer sufix. This config will run our date.service all days at 1:05am. We can check the timer running on a system with:

$ sudo systemctl list-timers
$ sudo systemctl list-timers --all

In Arch Linux, you can check as an example the logrotate's timer:

$ cat /usr/lib/systemd/system/logrotate.timer
[Unit]
Description=Daily rotation of log files
Documentation=man:logrotate(8) man:logrotate.conf(5)

[Timer]
OnCalendar=daily
AccuracySec=12h
Persistent=true

[Install]
WantedBy=timers.target

$ cat /usr/lib/systemd/system/logrotate.service
[Unit]
Description=Rotate log files
Documentation=man:logrotate(8) man:logrotate.conf(5)
ConditionACPower=true

[Service]
Type=oneshot
ExecStart=/usr/sbin/logrotate /etc/logrotate.conf

# performance options
Nice=19
IOSchedulingClass=best-effort
IOSchedulingPriority=7

# hardening options
#  details: https://www.freedesktop.org/software/systemd/man/systemd.exec.html
#  no ProtectHome for userdir logs
#  no PrivateNetwork for mail deliviery
#  no ProtectKernelTunables for working SELinux with systemd older than 235
MemoryDenyWriteExecute

It's recommended to use the option Persistent=true. It will run the unit automatically if the timer lost the previous start time. This could happen because the computer was turned off before the event could take place.