“ssh.service is not active, cannot reload” — Ubuntu's socket-activated SSH, explained
Since 22.10, sshd doesn't run until someone connects, so reload fails and set -e scripts die. Why Ubuntu changed it, the commands that work now, and the official way back.
Nothing is broken. Since Ubuntu 22.10, SSH uses systemd socket activation: ssh.socket listens on port 22 and ssh.service only starts when a connection actually arrives. Until then the service is inactive, so systemctl reload ssh fails with “ssh.service is not active, cannot reload” and exits non-zero, which is how it kills provisioning scripts running under set -e. Use systemctl restart ssh for config changes (restart activates; reload doesn’t), and for port changes on 24.04, reload the daemon and restart ssh.socket. Exact commands below.
What changed, and why
Ubuntu’s announcement is explicit: from openssh-server 1:9.0p1-1ubuntu1 in 22.10, “sshd will not be started until an incoming connection request is received.” The motive was memory on idle servers: about 3MiB saved per instance, which matters at VM-and-container fleet scale (Canonical measured a default container dropping from 65MiB to 58MiB). The design persists through 24.04 LTS, with a refinement: a systemd generator now reads /etc/ssh/sshd_config and configures ssh.socket to match, so your config file stays the source of truth for ports and addresses.
Why your script died
On a freshly provisioned server nobody has connected to yet, ssh.service is inactive by design. Ask systemd to reload an inactive unit and the client prints exactly this error (it’s a stock systemd message, not an SSH one) and returns non-zero. A hardening script that edits sshd_config and then runs systemctl reload ssh under set -e therefore dies at the finish line: after making its changes, before applying them. It reliably surprises anyone automating VPS setup, because on a machine you’ve been SSH’d into all day the service is active and reload works fine. The bug only exists on boxes nobody has touched: that is, in automation.
The commands that work
- Applying sshd_config changes:
sudo systemctl restart ssh. Ubuntu’s own server docs use restart, and restart starts an inactive service instead of erroring. - Changing the SSH port on 24.04: edit
Portin/etc/ssh/sshd_configas you always did, then per the package’s own README:systemctl daemon-reload→systemctl restart ssh.socket
(the generator translates your config into the socket’s listener; on 22.10–23.10 ports lived in socket drop-in files instead, a wrinkle to remember when old guides disagree). - Checking state:
systemctl status ssh.socket ssh.service. An inactive service beside a listening socket is the healthy default, not a fault.
Turning it off (the supported way)
If you’d rather have a permanently running sshd (some prefer the classic behavior for monitoring or consistency), the openssh package documents the exact revert on 24.04: mask the generator, then swap units.
mkdir -p /etc/systemd/system-generators/ ln -s /dev/null /etc/systemd/system-generators/sshd-socket-generator systemctl daemon-reload systemctl disable --now ssh.socket systemctl enable --now ssh.service
For an agent server there’s no strong reason to bother: socket activation costs one small first-connection delay and nothing else, and your hardening checklist (keys-only auth, a port audit from outside, equanimity about the login-attempt noise) works identically either way. Just teach your scripts the one rule: restart, don’t reload, on machines that may never have been touched.