Skip to content

SecurityServer hardening

SSH hardening: lock down OpenSSH on Ubuntu and Debian

Harden OpenSSH beyond the basics: a drop-in config, allowed users, login limits, idle timeouts, a safe port change with socket activation and optional 2FA.

  • Intermediate
  • 20 min read
  • Updated

Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 12, Debian 13

This guide is not available in your language yet, so it is shown in English.

On this page
  1. Before you start
  2. Step 1: Write a drop-in configuration
  3. Step 2: Check and apply
  4. Step 3: Change the port safely (optional)
  5. Step 4: Use a hardware-backed key (optional)
  6. Step 5: Add a one-time code (optional)
  7. Step 6: Watch the logs
  8. Troubleshooting
  9. Next steps

Securing a new server already turns off root and password logins. This guide goes further: it limits who may log in, how many tries they get, how long idle sessions live, moves SSH to another port safely and adds optional two-factor authentication. Commands are for Ubuntu 24.04/26.04 and Debian 12/13.

Before you start

  • Key-based login works for your sudo user (SSH keys).
  • You have a second way in, such as the web console if your service page shows one.
  • Keep one SSH session open throughout and test every change in a second terminal.

Step 1: Write a drop-in configuration

OpenSSH uses the first value it reads for each option, and Ubuntu and Debian read /etc/ssh/sshd_config.d/*.conf before the rest of the main file. Put all your settings in one file that sorts first:

Bash
sudo nano /etc/ssh/sshd_config.d/00-hardening.conf
Text
# Who may log in, and how
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AllowUsers alex

# Fewer tries, shorter waits
MaxAuthTries 3
LoginGraceTime 30

# Close idle or dead sessions
ClientAliveInterval 300
ClientAliveCountMax 2

# Features most servers do not need
X11Forwarding no
AllowAgentForwarding no

AllowUsers lists the accounts that may log in at all; separate several with spaces, or use AllowGroups with a group such as sshusers. Leave out AllowAgentForwarding no if you use agent forwarding on purpose.

Step 2: Check and apply

Bash
sudo sshd -t
sudo sshd -T | grep -E 'permitrootlogin|passwordauthentication|allowusers|maxauthtries'
sudo systemctl restart ssh

sshd -t must print nothing. sshd -T shows the values in effect; if one is not what you wrote, another file sets it first.

Verify: a new login as alex works; a login as any other user is refused with Permission denied.

Step 3: Change the port safely (optional)

A different port only reduces log noise, but if you want it, do it in this order. Allow the new port in the firewall before SSH moves:

Bash
sudo ufw allow 2222/tcp

Add the port to your drop-in file:

Text
Port 2222

Apply it:

Ubuntu

On Ubuntu, SSH is socket-activated: a generator reads Port from the configuration and sets up ssh.socket. Reload and restart the socket:

Bash
sudo sshd -t
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket

Debian

Bash
sudo sshd -t
sudo systemctl restart ssh

Verify: sudo ss -tlnp | grep 2222 shows the listener, and ssh -p 2222 [email protected] works from a new terminal. Only then remove the old rule: sudo ufw delete allow OpenSSH.

Step 4: Use a hardware-backed key (optional)

With a FIDO2 security key, create a key that needs the device and a touch, and with verify-required also its PIN:

Bash
ssh-keygen -t ed25519-sk -O verify-required

Add the public key to authorized_keys as usual. Keep a second key or a console in case the device is lost.

Step 5: Add a one-time code (optional)

Time-based codes add a second factor on top of the key. Install the PAM module and set it up as your user (not root):

Bash
sudo apt install libpam-google-authenticator
google-authenticator

Answer the questions, scan the QR code with your authenticator app and store the emergency codes safely. Then add this line to /etc/pam.d/sshd:

Text
auth required pam_google_authenticator.so

In your drop-in file, change KbdInteractiveAuthentication no to yes and require both factors:

Text
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

If you want SSH to ask only for the code and not also the account password, comment out the line @include common-auth in /etc/pam.d/sshd. Check with sudo sshd -t and restart SSH.

Verify: a new login asks for the key passphrase and then a Verification code. Test it before you close your other session.

Step 6: Watch the logs

Bash
sudo journalctl -u ssh --since today | grep -E 'Accepted|Failed|Invalid'

Accepted publickey for alex lines are your logins; check that you recognise every source address. Many Invalid user lines from random addresses are normal background scanning and harmless with these settings. To block repeat offenders automatically, see Fail2ban and CrowdSec.

Troubleshooting

Permission denied for your own user after Step 2. The name in AllowUsers does not match, or the user logs in with a different name. Fix the file from your open session.

The new port does not answer on Ubuntu. You restarted ssh instead of reloading the generator and the socket. Run sudo systemctl daemon-reload and sudo systemctl restart ssh.socket.

Two-factor prompts never appear. KbdInteractiveAuthentication is still no in an earlier file, or UsePAM is off. Check with sudo sshd -T | grep -E 'kbdinteractive|usepam|authenticationmethods'.

Locked out. Use the console and follow locked out after a firewall change.

Next steps

Frequently asked questions

Is changing the SSH port worth it?

It cuts the noise of automated scans in your logs, but it is not protection on its own. Do it if you like quieter logs, after allowing the new port in the firewall, and keep key-only logins as the real defence.

Why put the settings in sshd_config.d instead of sshd_config?

Package updates may replace the main file or ask you to merge changes. A drop-in file survives updates, and because OpenSSH uses the first value it reads, a file named 00-something takes precedence over later defaults.

Does two-factor authentication for SSH replace keys?

No, it adds to them. With AuthenticationMethods publickey,keyboard-interactive a login needs both the key and a code. Keep a tested fallback, such as the web console, before you turn it on.

How do I see the settings that are really in effect?

Run sudo sshd -T. It prints the final value of every option after all files have been read, which shows whether an earlier file overrides yours.

What is a hardware-backed SSH key?

A key of type ed25519-sk lives on a FIDO2 security key and only works while the device is plugged in and touched. Even if your computer is compromised, the key cannot be copied.

Sources

Gerar senha

Please confirm