Skip to content

Cookie settings

Choose which kinds of cookies you allow. You can change your choice at any time via Cookie settings at the bottom of every page. Privacy statement

Necessary

Always on

Needed to log in, keep your cart and remember your choices. These are always on.

Which cookies?
  • weboke_sessie, weboke_klant, weboke_remember: your session and staying logged in
  • weboke_basket: your cart
  • wkBtwIncl: showing prices with or without VAT
  • wok_cookies: your cookie choice, 12 months

Measures which ad leads to a visit or order, so we do not pay for ads that do nothing.

Which cookies?
  • Google Ads via Google Tag Manager (_gcl_au, _gcl_aw), up to 90 days
  • OpenAI Ads, ads in ChatGPT
  • wok_aff: which partner referred you to us (affiliate programme), 60 days

4.6

Country and language

Each country has its own site, with prices and VAT for that country.

View

Module 2 · 2.2

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:

  1. Two keys work (lesson 2.1), and you have checked in a new window that logging in with a key succeeds.
  2. 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.
  3. You know your provider's console: it lets you in without SSH.
  4. 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/*.conf

So 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 yes

Because 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 yes

Two 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.conf

with this content:

# Key-only login
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password

What 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 PasswordAuthentication set to no. Older guides call this setting ChallengeResponseAuthentication; since OpenSSH 8.7 that is a deprecated alias for the same thing. Debian already sets it to no by 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 set no once you are sure that logging in as that user and sudo both work.

Optional, if you want to go further:

AllowUsers anna
AuthenticationMethods publickey

AllowUsers 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 ssh

On 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.socket

If 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 ssh

If 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_config the first value wins; files in sshd_config.d are read first. Put your own settings in a file such as 00-beveiliging.conf.
  • Set PasswordAuthentication no and KbdInteractiveAuthentication no; root only with a key (prohibit-password) or not at all (no).
  • Check with sshd -t before reloading and with sshd -T which value really applies; watch out for a 50-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-reload and systemctl restart ssh.socket.

Quiz

1. At the bottom of /etc/ssh/sshd_config it says PasswordAuthentication no, but you can still log in with a password. What is the most likely cause?



2. Why do you set KbdInteractiveAuthentication no as well as PasswordAuthentication no?



3. What does PermitRootLogin prohibit-password mean?



4. Which order is the safest way to work?



5. On Ubuntu 24.04 you change the line Port 22 to Port 2222 and run systemctl restart ssh. With ss -tlnp you see it is still listening on 22. What did you forget?



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.

Exercise Z2.2: Password login is switched off

We don't log in and we don't try any password or key. First you show that the server is yours: click "Show my code" and put a file /.well-known/weboke-cursus-<code>.txt containing only that code on the web server of your hostname. We fetch it directly from every IP address we check (IPv4 and IPv6 separately); a TXT record doesn't count here. The check comes from heavy.webawere.nl (185.158.167.16 and 2a07:ae80:100:0:185:158:167:16), not from our web server. Only for registered students; at most 6 checks per hour per server. We only ask which login methods your server offers for your username, just as every SSH client does before logging in. Enter your own user: an unknown name shows up in your log as "Invalid user" and counts as one attempt for fail2ban.





What you enter and what we find isn't stored. Your browser remembers your answers and whether you've passed the exercise. If you're signed in, we only save that you got the exercise (almost) right in My courses; you can delete that there too.

Further reading

The steps in these articles apply to the WebOké VPS screen; other providers work in a similar way.

One moment…

Set up your domains

For each domain, arrange the nameservers, the link to your hosting and who becomes the owner.

Loading your domains…