Post

hardening SSH: the low-hanging fruit most people skip

A practical walkthrough of SSH hardening steps that meaningfully reduce your attack surface without breaking anything.

Project Description

SSH is the primary administrative interface for most Linux systems, which makes it one of the more consequential services to get right. The defaults are functional but not particularly secure. A few deliberate changes significantly reduce the attack surface, none of them require much effort, and most can be done in an afternoon.

This is documentation of the hardening steps I applied to my own systems, with reasoning for each.


Disable Password Authentication

This is the most important one. If password authentication is enabled, the server is permanently exposed to brute-force attacks. Fail2Ban helps, but the better fix is to not allow passwords at all.

In /etc/ssh/sshd_config:

1
2
PasswordAuthentication no
ChallengeResponseAuthentication no

Before applying this: make absolutely sure your key-based authentication is working. Testing in a second terminal session before closing your first is standard practice. Losing your only access path to a remote server is an avoidable lesson.


Change the Default Port

Port 22 is scanned constantly. Moving SSH to a non-standard port (anything above 1024, something memorable and not commonly scanned) dramatically reduces the noise in logs and removes you from automated scan-and-attack pipelines.

1
Port 2222

This is security through obscurity and not a substitute for actual hardening, but combined with the above it makes your server effectively invisible to the majority of opportunistic scanning. The logs become substantially quieter.

Update your firewall rules accordingly and remember to specify the port in your client config (~/.ssh/config) to avoid typing it every time.


Restrict Root Login

Direct root login should be disabled. If you need elevated access, log in as a normal user and escalate via sudo.

1
PermitRootLogin no

If you use certain automation tools that require direct root access (some backup agents, for instance), consider PermitRootLogin prohibit-password as a compromise, which allows key-based root login while blocking password attempts.


Limit Which Users Can Connect

1
AllowUsers yourusername

This creates an explicit allowlist. Even if another account exists on the system and has SSH access configured, it cannot connect unless it appears here. Principle of least privilege applied at the login layer.


Set an Idle Timeout

Sessions left open indefinitely are a risk. Two settings handle this:

1
2
ClientAliveInterval 300
ClientAliveCountMax 2

This sends a keepalive probe every 5 minutes and disconnects after 2 failed probes, so an idle session terminates after roughly 10 minutes of inactivity. Adjust to taste.


Disable Unused Features

Several SSH features that are enabled by default serve niche purposes and expand the attack surface unnecessarily:

1
2
3
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no

If you actively use X11 forwarding or SSH tunneling, keep what you need. Otherwise, disable it. Features you are not using cannot be exploited.


Use Stronger Key Types

When generating new key pairs, prefer Ed25519 over the older RSA:

1
ssh-keygen -t ed25519 -C "your-label"

Ed25519 keys are shorter, faster, and based on more modern elliptic curve cryptography. If you have old RSA-2048 keys floating around, this is a reasonable time to rotate them.


Apply Changes

After editing /etc/ssh/sshd_config, validate the config before restarting:

1
2
sudo sshd -t
sudo systemctl restart sshd

sshd -t exits cleanly if the config is valid or prints the error if not. Restarting with a broken config file will lock you out.


Security Relevance

Domain 1: Threats and Vulnerabilities Reducing the attack surface of the primary administrative interface directly limits the paths available for unauthorized access.

Domain 3: Implementation Configuration hardening is a foundational implementation control across every major security framework.

Summary

None of these steps are novel or complicated, but collectively they represent a meaningful improvement over defaults. A system with disabled password auth, a non-standard port, no root login, explicit user allowlisting, and idle timeouts is substantially harder to compromise than one running out-of-the-box SSH.

The cost is essentially zero. The return is significant.

This post is licensed under CC BY 4.0 by the author.