SSH is the main way to access a VPS. By default it runs on port 22 and is exposed to brute-force attacks. Proper configuration minimizes the risk of a breach.
A Secure /etc/ssh/sshd_config
># Change the default port (optional, but recommended)
Port 2222
# Disable root login
PermitRootLogin no
# Allow login only for specific users
AllowUsers deploy admin
# Disable password login (keys only!)
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
# Disable X11 forwarding
X11Forwarding no
# Idle session timeout (5 minutes)
ClientAliveInterval 300
ClientAliveCountMax 2
# IPv4 only (if you don't need IPv6)
AddressFamily inet
# SSH protocol 2 (the legacy protocol 1 is no longer used, but state it explicitly)
Protocol 2
# Encryption algorithms (modern)
KexAlgorithms curve25519-sha256,diffie-hellman-group14-sha256
Ciphers aes256-gcm@openssh.com,chacha20-poly1305@openssh.com
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com
Apply the Changes
# Check the syntax before restarting!
sudo sshd -t
# Restart SSH
sudo systemctl restart sshd
# Do not close the current session — open a new window and test the login
Generating and Adding SSH Keys
# On the client — generate a key (Ed25519 — modern and secure)
ssh-keygen -t ed25519 -C "myserver" -f ~/.ssh/myserver
# Copy the public key to the server
ssh-copy-id -i ~/.ssh/myserver.pub user@server.example.com
# Add the public key manually
mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
Fail2Ban — Protection Against Brute-Force
>sudo apt install fail2ban -y
# /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 2222 # your SSH port
maxretry = 5 # attempts before a ban
bantime = 3600 # ban for 1 hour
findtime = 600 # 10-minute window
sudo systemctl enable --now fail2ban
# View banned IPs
sudo fail2ban-client status sshd
- ✓ Key-only login (PasswordAuthentication no)
- ✓ PermitRootLogin no
- ✓ Non-standard port
- ✓ AllowUsers — only the users you need
- ✓ Fail2Ban active
- ✓ UFW allows SSH only from the IPs you need
Common SSH hardening mistakes
Most SSH problems after hardening fall into two buckets — "the server won't start" and "access is lost" — and it matters which one you're dealing with.
sshd: no hostkeys available -- exiting.
The service can't find the host key files — typical after manually deleting or moving /etc/ssh/ssh_host_*_key. Regenerate them: ssh-keygen -A, then restart sshd.
Permission denied (publickey).
This exact error shows up when PasswordAuthentication no was applied before the public key was actually added and verified in a new session. That ordering is the difference between a working server and lost access. Always test key-based login in a separate window BEFORE disabling passwords, as noted in the instructions below.
/etc/ssh/sshd_config line 27: Bad configuration option: Protocol
The Protocol 2 directive in the example configuration above is a leftover from old versions. As of OpenSSH 7.6 it's deprecated, and some OpenSSH 8.0+ builds reject the line outright during syntax checking. SSH protocol version 1 was removed from the code long ago, and version 2 is used by default with no need to state it — just remove the line from the config.
Authentication methods compared
| Method | Brute-force resistance | Convenience | Compromise risk |
|---|---|---|---|
| Password | Low | High (no file needed) | Guessing, leaks, phishing |
| SSH key (Ed25519) | High | Needs access to the private key | Theft of the key file |
| Key + passphrase | Very high | Requires entering a passphrase | Minimal even if the file is stolen |
| SSH certificates (CA) | Very high | Requires CA infrastructure | Minimal, revocable |
An Ed25519 key is enough for a single VPS. For server fleets of 10+ machines, it's worth looking at SSH certificates — they save you from adding and revoking keys on every server one by one.
When strict hardening doesn't fit
Changing the port reduces log noise from automated scanners — it's not protection against a targeted attack: if an attacker already knows the IP and is targeting that specific server, scanning the port range takes seconds. Don't treat a non-standard port as a substitute for the other measures. Disabling PermitRootLogin can break installers for legacy control panels that expect direct root SSH access — before hardening, check whether the software you're running needs that kind of access during first install or upgrade. If an external team manages the server under a corporate policy requiring password access over VPN, disabling PasswordAuthentication means first agreeing on a switch to keys with everyone who logs in.
How to verify the result
Check more than "the connection worked" — confirm what actually took effect on the server:
# Check that sshd is listening on the new port
sudo ss -tlnp | grep sshd
# Check fail2ban's status for sshd
sudo fail2ban-client status sshd
# Verbose connection output — shows which key is being used
ssh -v -p 2222 user@server.example.com
In the ssh -v output, look for the line Authentication succeeded (publickey) — if the server asks for a password instead, either PasswordAuthentication no hasn't taken effect yet, or the key isn't in the authorized_keys file of the user you're logging in as.