Symptom

A freshly-installed krill server only ever had the self-signed TLS certificate that postinst generates. On a host with a real, public domain name there was no supported path to a browser-trusted certificate — operators either lived with the browser warning / manual /trust cert install, or hand-rolled their own certbot wiring and re-discovered every time where the server actually reads its cert from.

Root cause

The certificate story was intentionally minimal (self-signed, generated once at install), and the paths the server reads (/etc/krill/certs/krill.crt, krill.key, .pfx_password) were only produced by postinst. There was no first-class, documented way to swap in a real cert without knowing the implementation detail that the running server builds its keystore from the PEM files, not from krill.pfx (see KtorConfig.kt::envConfig / loadKeyStoreFromPemkrill.pfx is written by postinst but never read at runtime; only .pfx_password is).

Fix

Added server/package/usr/local/bin/krill-enable-letsencrypt: a POSIX-sh helper an operator runs post-install (sudo krill-enable-letsencrypt <domain> --email <addr>). It installs certbot if missing, obtains a cert via the ACME HTTP-01 standalone challenge (port 80 is free — krill only uses 8442), copies fullchain.pemkrill.crt and privkey.pemkrill.key with krill:krill ownership (key 600, cert 644), refreshes krill.pfx best-effort for coherence, and restarts krill.service. It also installs a certbot deploy hook scoped to a stored .letsencrypt_domain, so the 90-day auto-renewals re-apply the cert and restart krill with no manual step. postinst gained a defensive chmod +x for the new script (matching the camera/kiosk pattern) and a banner hint pointing operators at it.

Prevention