Linux Server Hardening Checklist

Chapter 2 of 7 · 7 checks · 4 min

SSH

Checks on the front door: key-only logins, no root, a tested configuration and as little exposure as possible.

Show
  1. SSH accepts keys only: password and keyboard-interactive logins are offMust

    Why it matters and how to check

    Any server with SSH open to the internet receives constant password guessing. The OpenSSH defaults for PasswordAuthentication and KbdInteractiveAuthentication are both yes, so you have to turn them off yourself. With keys only, guessing has nothing to guess.

    To verify: print the effective configuration with sudo sshd -T and check that passwordauthentication no and kbdinteractiveauthentication no appear. From another machine, try ssh -o PubkeyAuthentication=no user@server. It must fail with Permission denied (publickey) and never offer a password prompt.

    Example

    Shell
    # /etc/ssh/sshd_config.d/10-hardening.conf
    PasswordAuthentication no
    KbdInteractiveAuthentication no
    PermitRootLogin no
    PermitEmptyPasswords no
    
    sudo sshd -T | grep -Ei 'passwordauthentication|kbdinteractive|permitrootlogin'
  2. Root cannot log in over SSHMust

    Why it matters and how to check

    The OpenSSH default for PermitRootLogin is prohibit-password, which still allows root to log in with a key. Some cloud images add root keys at boot. Set it to no so every session starts as a named user and escalates with sudo.

    To verify: sudo sshd -T | grep permitrootlogin should print permitrootlogin no. Then try ssh root@server from your machine: it must be refused even if a key exists in /root/.ssh/authorized_keys. Empty that file too, so turning the setting back on by accident does not reopen access.

  3. SSH changes go in a drop-in file and are tested before restartMust

    Why it matters and how to check

    On Ubuntu, the main sshd_config includes /etc/ssh/sshd_config.d/*.conf at the top, and OpenSSH uses the first value it finds for most options. That means a drop-in wins over the main file, and a cloud image's own drop-in can silently override your setting. The Ubuntu docs warn that an invalid directive can stop sshd from starting and lock you out.

    To verify: put your settings in one file such as 10-hardening.conf and list the directory for others that conflict. Run sudo sshd -t before every restart; it must print nothing. Keep your current session open, restart with sudo systemctl restart ssh (sshd on RHEL), and confirm a new login works from a second terminal before closing the first.

    Example

    Shell
    ls /etc/ssh/sshd_config.d/
    sudo sshd -t && sudo systemctl restart ssh
    # open a NEW terminal and log in before closing the old one
  4. Only members of a named group can log in over SSHShould

    Why it matters and how to check

    By default any account with a valid key or shell can log in over SSH, including service accounts that should never be used interactively. AllowGroups turns this into an allowlist: only members of the listed groups can connect, and new system accounts are excluded automatically.

    To verify: create a group such as sshusers, add each admin, and set AllowGroups sshusers in your drop-in. Run sudo sshd -T | grep allowgroups. Try to log in as an account outside the group (for example a test user with a key): it must be refused, and journalctl -u ssh should show the denial.

  5. Admin keys are Ed25519, passphrase protected, and authorized_keys is not writable by othersShould

    Why it matters and how to check

    The Ubuntu docs recommend Ed25519 keys (or 4096-bit RSA) and a passphrase on the private key, with an agent so you do not retype it. An authorized_keys file that group or others can write lets another local user add their own key to your account.

    To verify: check each key type in authorized_keys; it should start with ssh-ed25519 or sk-ssh-ed25519 for hardware keys, not ssh-dss or short RSA keys. Run ls -l ~/.ssh/authorized_keys and confirm it is not group or world writable (chmod go-w fixes it). Ask each admin to confirm their private key has a passphrase.

    Example

    Shell
    ssh-keygen -t ed25519 -C "alice@laptop"
    ssh-copy-id -i ~/.ssh/id_ed25519.pub alice@server
    chmod go-w ~/.ssh ~/.ssh/authorized_keys
  6. SSH is reachable only from known networks, or not exposed at allShould

    Why it matters and how to check

    Key-only SSH is strong, but every exposed service is something that can have a vulnerability. Limit who can reach port 22: a cloud firewall or security group that allows only your office or VPN range, a bastion host, or a tool such as a cloud provider's session manager that needs no inbound port at all.

    To verify: from a network outside your allowlist (a phone hotspot works), run nc -zv server 22. It should time out. In the cloud console, check the inbound rules for port 22 and confirm none allow 0.0.0.0/0 or ::/0. Recent OpenSSH also applies PerSourcePenalties by default, which temporarily refuses sources that keep failing; leave it on.

  7. Unused SSH features such as forwarding and version banners are turned offNice to have

    Why it matters and how to check

    Agent forwarding, TCP forwarding and X11 forwarding are useful on some hosts and unnecessary on most app servers. The OpenSSH default for AllowTcpForwarding is yes. On Ubuntu, DebianBanner no stops the server announcing its exact OS version before login, which the Ubuntu docs suggest. A lower MaxAuthTries than the default of 6 also reduces noise.

    To verify: in sudo sshd -T, check allowtcpforwarding no, allowagentforwarding no, x11forwarding no and, on Ubuntu, debianbanner no, unless you have written down a reason to keep one. Run nc server 22 and read the banner line that comes back.

    Example

    Shell
    # /etc/ssh/sshd_config.d/10-hardening.conf (continued)
    AllowTcpForwarding no
    AllowAgentForwarding no
    X11Forwarding no
    MaxAuthTries 3
    DebianBanner no   # Ubuntu and Debian only