Module 2 · 2.2
English
Configuring the SSH server securely
Module 2: SSH and keys · Reading time: 12 minutes
Learning objective: After this lesson you can switch off password login and root login with a password, check which setting really applies, and do this without locking yourself out.
Key concepts: sshd, sshd_config, sshd_config.d, first value wins, PasswordAuthentication, KbdInteractiveAuthentication, PermitRootLogin, AuthenticationMethods, AllowUsers, sshd -t, sshd -T, second session, cloud-init, ssh.socket
First, the safety net
This lesson closes a door you need to get through yourself. One typo can mean you can no longer get in. So always do this before you start:
- Two keys work (lesson 2.1), and you have checked in a new window that logging in with a key succeeds.
- A snapshot of your VPS. At WebOké you create it in the VPS screen; other providers also call it a snapshot or image. If something goes wrong, you restore it.
- You know your provider's console: it lets you in without SSH.
- Your current SSH session stays open until the end. A running session keeps working when you change the settings or reload the service. You test every change in a second window.
Where the settings live
The SSH server is called sshd. Its settings are in /etc/ssh/sshd_config. On Debian and Ubuntu, this line is at the top of that file:
Include /etc/ssh/sshd_config.d/*.confSo all files ending in .conf in the sshd_config.d directory are read before the rest of the main file, in alphabetical order. That is handy: you put your own settings in a file of your own and leave the main file alone, so a package update doesn't touch your changes.
But it has a consequence that catches many people out. In sshd_config, for each setting, the first value sshd comes across is the one that counts. Later lines with the same setting are ignored. So if you put PasswordAuthentication no at the bottom of sshd_config, it does not win over a file in sshd_config.d that says yes.
The cloud-init trap
Many VPS images are set up by cloud-init on first boot. Depending on how the image and the installation are configured, cloud-init writes a file such as /etc/ssh/sshd_config.d/50-cloud-init.conf containing, for example:
PasswordAuthentication yesBecause that file is read before the main file, password login stays on, whatever you put in sshd_config. So don't assume; take a look:
root@web1:~# grep -ri passwordauthentication /etc/ssh/sshd_config /etc/ssh/sshd_config.d/
/etc/ssh/sshd_config:#PasswordAuthentication yes
/etc/ssh/sshd_config.d/50-cloud-init.conf:PasswordAuthentication yesTwo clean solutions: change that file to no, or put your own settings in a file that comes earlier in the alphabet, such as 00-beveiliging.conf. A file called 99-mijn.conf does not work, because by then cloud-init has already won.
The settings that matter
Create your own file:
root@web1:~# nano /etc/ssh/sshd_config.d/00-beveiliging.confwith this content:
# Key-only login
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-passwordWhat does each line mean?
- PasswordAuthentication no: the server no longer accepts a password. The OpenSSH default is
yes. - KbdInteractiveAuthentication no: "keyboard-interactive" is a second way of asking for a password, via PAM. If you leave it on, someone can still try a password, even with
PasswordAuthenticationset tono. Older guides call this settingChallengeResponseAuthentication; since OpenSSH 8.7 that is a deprecated alias for the same thing. Debian already sets it tonoby default, but add it anyway: it makes things clear and it is also correct on other systems. - PermitRootLogin prohibit-password: root may log in, but only with a key. This has been the default since OpenSSH 7.0. Stricter is
PermitRootLogin no: root can't get in via SSH at all, you log in as a normal user and use sudo (lesson 3.2). Only setnoonce you are sure that logging in as that user andsudoboth work.
Optional, if you want to go further:
AllowUsers anna
AuthenticationMethods publickeyAllowUsers only lets the named users in; any other name is refused, even with a valid key. Handy, but don't forget yourself, and remember to update it when you add a second administrator. AuthenticationMethods publickey says in one line that only keys are accepted.
Test, apply, check
First let sshd check the file. This starts nothing and changes nothing:
root@web1:~# sshd -t
root@web1:~#No output means no errors. If there is a typo, you see the line and the file. Only then do you reload the service:
root@web1:~# systemctl reload sshOn Debian and Ubuntu the service is called ssh, on AlmaLinux and Rocky Linux sshd.
Next, check which value really applies. sshd -T shows the complete, resolved configuration, with all Include files processed:
root@web1:~# sshd -T | grep -Ei 'passwordauth|kbdinteractive|permitrootlogin'
permitrootlogin without-password
passwordauthentication no
kbdinteractiveauthentication no(without-password is the old name for prohibit-password. OpenSSH versions before 10.1, such as on Debian 13 and Ubuntu 24.04, still show the old name; newer ones show prohibit-password. It means the same thing.)
And now the most important part: test in a second window, while the first one stays open.
anna@laptop:~$ ssh anna@192.0.2.10
anna@web1:~$If that works, deliberately try to log in with a password. This must fail:
anna@laptop:~$ ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no anna@192.0.2.10
anna@192.0.2.10: Permission denied (publickey).After Permission denied, the brackets show which login methods the server still offers. If it only says publickey, you're good. If password or keyboard-interactive also appears, a different value still applies somewhere: check again with sshd -T.
That exact list is also what the course exercise checks, from the outside. With every connection, your SSH client first asks which methods are allowed, using a request of the type "none". The server replies with the list, without any password or key being tried.
Ubuntu 24.04 and later: ssh.socket
On Ubuntu since 22.10, it is not sshd itself listening on port 22 but systemd, via ssh.socket. Only when a connection comes in does systemd start the SSH service. For the settings in this lesson that makes no difference: systemctl reload ssh or restart ssh is enough.
It does matter if you change the port or the listen address (Port, ListenAddress). Since Ubuntu 24.04, systemd reads those values from sshd_config, but only after:
root@web1:~# systemctl daemon-reload
root@web1:~# systemctl restart ssh.socketIf you forget this, the server simply keeps listening on the old port. Worse: if you first set your firewall to a new port while SSH stays on the old one, you lock yourself out. Always check with ss -tlnp | grep ssh what is really being listened on (lesson 5.1), and open the new port in your firewall before you close the old one. Whether a different port makes sense is covered in lesson 2.3.
If it goes wrong anyway
If you can't get in any more, open your provider's console, log in as root (with the password, because the console is a "keyboard attached to the server", not SSH) and roll back your file:
root@web1:~# mv /etc/ssh/sshd_config.d/00-beveiliging.conf /root/
root@web1:~# systemctl reload sshIf that doesn't work either, restore the snapshot. At WebOké you can also set a new root password in the VPS screen; other providers often have a similar button or a rescue mode.
On AlmaLinux and Rocky Linux
The service is called sshd (systemctl reload sshd). There too, an Include /etc/ssh/sshd_config.d/*.conf sits at the top and the system ships its own files in that directory; the same "first value wins" rule applies. If you change the port, SELinux must also allow that port (semanage port -a -t ssh_port_t -p tcp 2222) and firewalld must open it.
Summary
- In
sshd_configthe first value wins; files insshd_config.dare read first. Put your own settings in a file such as00-beveiliging.conf. - Set
PasswordAuthentication noandKbdInteractiveAuthentication no; root only with a key (prohibit-password) or not at all (no). - Check with
sshd -tbefore reloading and withsshd -Twhich value really applies; watch out for a50-cloud-init.conf. - Test in a second window and keep the first session open. Know the console and take a snapshot beforehand.
- On Ubuntu 24.04+, a different port requires
systemctl daemon-reloadandsystemctl restart ssh.socket.
Quiz
Exercise
Exercise Z2.2: Password login is switched off. Switch off password login and keyboard-interactive as described in this lesson, then let the program check from the outside. Enter your server's IP address or hostname, the SSH port (22 by default) and the username you log in with yourself (for example anna, not root or a made-up name). The program does not log in: like any SSH client before logging in, it only asks which login methods your server offers for that user. The correct result is: only publickey.
Further reading
The steps in these articles apply to the WebOké VPS screen; other providers work in a similar way.
- Securing your VPS: the first five minutes
- No access to your VPS anymore: what now?
- Snapshots and backups of your VPS
- sshd_config manual: https://man.openbsd.org/sshd_config
- Ubuntu: SSHd now uses socket-based activation: https://discourse.ubuntu.com/t/sshd-now-uses-socket-based-activation-ubuntu-22-10-and-later/30189
