Run sudo sshd -t. It names the file and line that broke. Fix that line, then sudo systemctl reload ssh. Do this from a session you already have open, and read the warning below before you restart anything.
$ sudo sshd -t /etc/ssh/sshd_config line 97: Directive 'UsePAM' is not allowed within a Match block
Before you touch sshd on a remote machine
This is the one service on this list that can lock you out of the server permanently. Your current SSH session survives a failed restart, because an established connection is handled by a forked child that keeps running after the parent dies. The danger is closing that session and discovering sshd never came back.
Three rules, in order of importance:
- Keep your existing session open. Do not log out until you have confirmed a new connection works. Open a second terminal and connect again as the test, rather than reconnecting with the only session you have.
- Always run
sshd -tbefore restarting. It costs nothing and catches the majority of causes below. - Prefer
reloadoverrestart. A reload re-reads the configuration without dropping the listening socket, so a mistake leaves the working daemon running.
If the machine has a serial or provider console, confirm you can reach it before changing sshd_config at all. That console is the difference between a two minute fix and a rebuild.
The causes, in order of how often they appear
- A directive in the wrong place. Most
sshd_configoptions are only valid at the top level, and a surprising number of guides show them being added at the end of a file that already contains aMatchblock. Everything after aMatchline belongs to that block until the next one, so an option appended to the bottom of the file silently lands inside it.UsePAM,PermitRootLoginandPortare the usual casualties. Move the directive above the firstMatch. - Missing privilege separation directory. The error is
Missing privilege separation directory: /run/sshd. Because/runis a tmpfs it is empty after every boot, so this appears on reboot even though nothing was edited. Creating it by hand works until the next restart; the durable fix is a tmpfiles rule:echo 'd /run/sshd 0755 root root -' | sudo tee /etc/tmpfiles.d/sshd.conf sudo systemd-tmpfiles --create
- Host keys missing or unreadable. sshd will not start without them. Regenerate on Debian and Ubuntu with
sudo dpkg-reconfigure openssh-server, or on any distribution withsudo ssh-keygen -A. Note that replacing host keys makes every existing client warn about a changed fingerprint, so only do this if the keys are genuinely gone. - Port 22 already bound. Usually a stale sshd that survived a bad shutdown, or socket activation already holding the port:
sudo ss -tlnp | grep ':22 ' systemctl status ssh.socket
On recent Ubuntu,
ssh.socketmay own the port instead ofssh.service. If socket activation is enabled, thePortdirective insshd_configis ignored entirely and the listening port is set in the socket unit instead. This surprises people who change the port and see no effect. - SELinux blocking a non-standard port. On RHEL, Rocky and Alma, moving sshd off port 22 fails until SELinux is told:
sudo semanage port -a -t ssh_port_t -p tcp 2222.
Reading the exit code
status=255 is sshd’s own general failure code and normally means a configuration problem, so run sshd -t. status=1/FAILURE covers most other startup rejections. status=226/NAMESPACE points at a unit drop-in with sandboxing directives rather than at sshd_config at all: inspect it with systemctl cat ssh. The full table is in the nginx version of this error.
How to stop it happening again
sudo sshd -t && sudo systemctl reload ssh
Make that one line a habit and this error stops being frightening. The test exits non-zero on a bad configuration, so the reload never runs against a file that would take the daemon down. For a change you are genuinely unsure about, start a second sshd on a spare port first, confirm you can log in on it, and only then edit the real one.
Related
- Job for nginx.service failed: the same systemd error, plus the full exit-code table.
- Job for docker.service failed: another service where socket activation changes how you stop and debug it.
- OpenSSL command generator: for the certificate and key work that often sits alongside SSH hardening.
I changed Port in sshd_config and nothing happened
Socket activation. On recent Ubuntu releases ssh.socket owns the listening port and sshd_config‘s Port directive is ignored. Edit the socket unit instead with sudo systemctl edit ssh.socket, set ListenStream= to clear the default and then to your port, and restart ssh.socket. Check which applies with systemctl status ssh.socket.
sshd -t passes but the service still will not start
Then it is not the configuration file. The remaining candidates are the privilege separation directory, missing host keys, the port being held by something else, and a unit drop-in. Run sudo journalctl -xeu ssh.service --no-pager | tail -40 and read the last lines before the exit: all four of those name themselves clearly in the journal.
Leave a Reply