automatic certbot renewal with NixOS and systemd
2023-04-21
I asked gpt-3.5-turbo. There was a lot of content missing, but in conjunction with the ArchWiki, the NixOS options search, and the man pages for systemd.service(5), systemd.unit(5) and systemd.timer(5) gave me enough to finish.
Here's how it looks:
systemd.services."certbot-renew" = {
description = "Renew certbot certificates";
script = ''
#!/usr/bin/env sh
${pkgs.certbot-full}/bin/certbot renew --verbose
'';
serviceConfig = {
Type = "oneshot";
Restart = "on-failure";
RestartSec = "1d";
ExecStartPost = "systemctl reload nginx.service";
};
after = [ "network.target" ];
};
systemd.timers."certbot-renew" = {
description = "Run certbot renewal once a month";
timerConfig = {
OnCalendar = "monthly";
RandomizedDelaySec = "86400s";
Persistent = true;
Unit = "certbot-renew.service";
};
wantedBy = [ "timers.target" ];
after = [ "network.target" ];
};Explanations are as follows:
Typeis set tooneshotso that the service is tied to the successful execution of thecertbot renewcommand.- Since this is
oneshotwe can reload nginx automatically withExecStartPost. - I set
RandomizedDelaySecbecause otherwise "monthly" means "at the start of each month". certbot includes some automated randomised jitter when being run automatically, but I assume that they otherwise get a lot of traffic on-the-hour. - WantedBy timers.target is needed to actually activate the timer.
- After network.target is just for safety in case this launches on boot.
It works!
NEXT LEFT LAST PASSED UNIT ACTIVATES
Wed 2023-04-19 19:00:00 UTC 43min left Wed 2023-04-19 18:00:07 UTC 16min ago logrotate.timer logrotate.service
Thu 2023-04-20 12:39:47 UTC 18h left Wed 2023-04-19 12:39:47 UTC 5h 36min ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Mon 2023-05-01 11:14:34 UTC 1 week 4 days left Wed 2023-04-19 17:42:41 UTC 34min ago certbot-renew.timer certbot-renew.servicebonus content: systemd-run
I used to run actions at particular times of day with the following command, hacked up in a frenzy:
sleep $(( $(date -d '23:35' +%s) - $(date +%s) )) && curl -X POST https://example.com/api/successSleeping until a certain time is brittle to clock drift (e.g. if my laptop is suspended before the command can run). I was aware of the at function, but reading through the ArchWiki gave showed me the systemd-run command, which sets a systemd timer to do the thing:
systemd-run --user --on-calendar=23:35 curl -X POST https://example.com/api/successCleaner and more reliable! The results can be viewed with journalctl.