Skip to content

// docs · reloading

Reloading services on renewal

SysCert delivers files and gets out of the way; it never restarts your services. This is how to have each consumer pick up a renewed certificate itself, the clean systemd way.

SysCert writes files and never runs commands: no reloads, no restarts, no post-hooks. That keeps this least-privilege service from having to poke at arbitrary daemons (see Distributing for the delivery model). The flip side is that you wire each consumer to pick up its new certificate.

Most services do not auto-reload

People often assume nginx or Apache will notice a changed cert file on their own. They don’t. Both read the certificate and key once, at start or reload, and hold them in memory. After a renewal overwrites the files, the old cert keeps being served until the service is told to reload. Same story for HAProxy, Postfix, Dovecot, and most others. A few servers do watch their cert files (Caddy and Traefik, which run their own ACME), but they’re the exception.

So for almost everything, you need a small nudge after each renewal.

The pattern: a systemd.path watcher

Have systemd watch the cert file SysCert delivers, and run a reload when it changes. That’s two units per service: a .path that watches, and a oneshot .service that reloads:

# /etc/systemd/system/nginx-reload.path
[Path]
PathChanged=/etc/nginx/tls/fullchain.pem   # the path SysCert distributes to

[Install]
WantedBy=multi-user.target
# /etc/systemd/system/nginx-reload.service
[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl reload nginx

Enable the .path, not the service; it starts the service on each change:

sudo systemctl enable --now nginx-reload.path

Now every time SysCert re-delivers fullchain.pem, systemd reloads nginx, with no privileged hook inside SysCert.

  • Watch the path the consumer actually reads: your [[distribute]] target, not the central store (which the service can’t read anyway).
  • PathChanged= fires when the file is closed after writing (good for SysCert’s atomic replace); PathModified= is noisier. To watch a whole directory, point PathModified= at it or use DirectoryNotEmpty=.

Reload command per service

Swap the ExecStart= (or the watched path) to match the consumer:

ServiceReload commandNotes
nginxsystemctl reload nginxor nginx -s reload (SIGHUP)
Apache (httpd)systemctl reload httpdapachectl graceful
HAProxysystemctl reload haproxygraceful; needs the key+cert in one PEM — use a bundle artifact
Postfixsystemctl reload postfixre-reads smtpd_tls_* certs
Dovecotsystemctl reload dovecot
Cockpitsystemctl restart cockpitreload not supported; restart is quick
PostgreSQLsystemctl reload postgresqlor SELECT pg_reload_conf(); — re-reads ssl_cert_file/ssl_key_file

If a daemon can’t reload TLS material without a full restart, point the .service at restart instead. The .path mechanism is identical either way.


Next: Distributing certs · Configuration