Skip to content
Back to Blog
Security11 min read

Harden SSH VPS Best Practices That Actually Work (2026)

Real production SSH hardening from years of support tickets: key-only auth, port changes, fail2ban tuning, and the anti-patterns that still leave servers exposed.

Written by Abdul AbrorTechnical Hosting Support Engineer
Harden SSH VPS Best Practices That Actually Work (2026)
On this page

Every unpatched VPS with password authentication gets hit within hours of going live. I've watched it happen in real time through auth logs: thousands of login attempts from botnets scanning common ports, trying root with password lists pulled from years of breaches. Most new VPS owners think a strong password is enough. It's not.

This guide covers the hardening steps that hold up in production, the ones I configure on every server I touch, and the common approaches that waste time or create false security.

Disable password authentication completely

Passworded SSH is the single biggest attack surface. Even a 32-character random password is still guessable given enough attempts, and fail2ban only slows brute force—it doesn't eliminate the risk. The only defensible approach is key-only authentication.

Generate an ED25519 key pair on your local machine if you haven't already:

ssh-keygen -t ed25519 -C "your-identifier"

Copy the public key to your server:

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-vps-ip

Test the key login in a new terminal session before locking yourself out. Once confirmed, edit /etc/ssh/sshd_config:

PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no

Restart SSH:

systemctl restart sshd

From that point forward, no password will work. Attackers scanning for weak credentials hit a wall.

One mistake I see often: admins disable PasswordAuthentication but leave ChallengeResponseAuthentication enabled, which can still allow keyboard-interactive password prompts depending on PAM configuration. Turn off both. And back up your private key—lose it and you're locked out.

Change the default port (yes, it helps)

Port 22 gets hammered constantly. Changing it doesn't stop a determined attacker, but it does drop automated scan traffic by 99%. Your auth logs go from thousands of failed attempts per day to nearly zero.

Pick a high port between 10000 and 65535 that isn't used by another service. Edit /etc/ssh/sshd_config:

Port 52847

Restart SSH, then test the new port before closing your current session:

ssh -p 52847 user@your-vps-ip

Update your firewall rules to allow the new port and block the old one. If you're using UFW:

ufw allow 52847/tcp
ufw delete allow 22/tcp
ufw reload

Some security purists call this "security through obscurity" and dismiss it. In production, reducing noise in your logs and cutting down on brute force attempts is a practical win. You're not relying on obscurity alone—you've already disabled password auth.

Lock down root login

Root should never log in via SSH. Create a regular user, give it sudo privileges, and disable root SSH access entirely. In /etc/ssh/sshd_config:

PermitRootLogin no

If you need to perform administrative tasks, SSH in as your regular user and escalate with sudo. This limits the blast radius if your key is ever compromised and gives you an audit trail in auth logs showing which user account was used.

On some distros, root login is already disabled by default. Check your config and confirm it's set to no, not prohibit-password or without-password, which still allow key-based root login.

Configure fail2ban properly

Fail2ban watches your auth logs and bans IPs after repeated failed login attempts. It's not a replacement for key-only auth, but it adds another layer and blocks low-effort scans.

Install it:

apt install fail2ban  # Debian/Ubuntu
yum install fail2ban  # CentOS/RHEL

Create /etc/fail2ban/jail.local and configure the SSH jail:

[sshd]
enabled = true
port = 52847
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600

This bans an IP for one hour after three failed attempts within ten minutes. Adjust maxretry, bantime, and findtime based on your tolerance for false positives. If you're the only one connecting, you can be aggressive. If you manage a team, give more room for typos.

Start and enable the service:

systemctl enable --now fail2ban

Check banned IPs:

fail2ban-client status sshd

One thing to watch: if you change your SSH port, update the port setting in jail.local to match. Otherwise fail2ban monitors the wrong port and does nothing.

Restrict SSH access by IP when possible

If you connect from a static IP or a small set of known IPs, whitelist them and block everything else. This is the most effective control after key-only auth. Use your firewall:

ufw default deny incoming
ufw allow from 203.0.113.50 to any port 52847 proto tcp
ufw enable

For teams or remote workers on dynamic IPs, IP whitelisting becomes impractical. In that case, combine key auth, a non-standard port, and fail2ban. It's not as airtight as an IP whitelist, but it's orders of magnitude better than default SSH with passwords.

Disable unused SSH features

SSH has options most servers never need. Turn them off. In /etc/ssh/sshd_config:

X11Forwarding no
AllowTcpForwarding no
PermitTunnel no
GatewayPorts no

X11 forwarding is rarely used on headless VPS instances and opens unnecessary network exposure. TCP forwarding and tunneling are powerful features but also allow pivoting and lateral movement if an account is compromised. Disable them unless you have a specific need.

Also set:

PermitEmptyPasswords no
MaxAuthTries 3
MaxSessions 2

These limit the number of authentication attempts per connection and concurrent sessions per user. Small constraints, but they reduce the window for abuse.

Keep SSH and the OS patched

Every few years a high-severity SSH vulnerability surfaces. Patches come out quickly, but unpatched servers stay exposed for months. I've seen production VPSs running OpenSSH versions from years ago, still vulnerable to public exploits.

Enable automatic security updates or set a weekly reminder to run:

apt update && apt upgrade -y     # Debian/Ubuntu
yum update -y                    # CentOS/RHEL

Check your OpenSSH version:

ssh -V

If it's more than a year old, you're likely missing important fixes. SSH hardening means nothing if the daemon itself is exploitable.

Use SSH key passphrases and ssh-agent

An unencrypted private key sitting on your laptop is a liability. If someone gets filesystem access—through malware, a stolen device, or a backup—your key is compromised. Encrypt it with a strong passphrase during key generation or add one later:

ssh-keygen -p -f ~/.ssh/id_ed25519

Then use ssh-agent to cache the decrypted key in memory so you only type the passphrase once per session:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

This balances security and convenience. Your key is encrypted at rest but available for repeated SSH connections without re-entering the passphrase every time.

Anti-patterns that don't help much

Running SSH on port 443 or 80 to "bypass firewalls": This confuses web traffic and SSH traffic, breaks some monitoring tools, and offers no real security benefit. If you need SSH from a restricted network, use a proper VPN or SSH over a secure tunnel, not port masquerading.

Installing a port knock daemon: Port knocking adds complexity and a new attack surface. If an attacker sniffs your knock sequence, they're in. If you forget the sequence or misconfigure it, you're locked out. Key-only auth and IP whitelisting are simpler and more reliable.

Relying solely on fail2ban: Fail2ban is a speed bump, not a wall. A slow, distributed brute force attack can stay under the threshold indefinitely. It's useful, but only as part of a layered defense.

Using AllowUsers or AllowGroups but leaving password auth enabled: Restricting which accounts can SSH in is good, but if those accounts still allow password login, you haven't solved the problem. Always disable passwords first.

Monitor auth logs and set up alerts

Even with hardening in place, check your logs. Failed key attempts, successful logins from unexpected IPs, and privilege escalation patterns all show up in /var/log/auth.log or /var/log/secure.

Grep for recent SSH activity:

grep sshd /var/log/auth.log | tail -50

Set up log monitoring with something like Logwatch or a centralized logging stack if you manage multiple servers. You want to know within hours if something abnormal happens, not weeks later during a forensic investigation.

What to audit first

Start with these checks on any inherited VPS:

  1. Is PasswordAuthentication set to no?
  2. Is PermitRootLogin set to no?
  3. Are you running the latest OpenSSH version?
  4. Is SSH listening on a non-standard port?
  5. Is fail2ban installed, enabled, and configured for your SSH port?
  6. Are there any weak or old SSH keys in ~/.ssh/authorized_keys?

Fix those six items and you've closed the most common entry points. The rest is tuning and monitoring.

Frequently asked questions

What if I lose my SSH key?
You'll need console access through your hosting provider's panel (VNC, KVM, or serial console). Log in that way, add a new public key to ~/.ssh/authorized_keys, and test. Always keep a backup of your private key in a secure password manager or encrypted storage.

Should I use RSA or ED25519 keys?
ED25519 is faster, smaller, and more secure than RSA. Use it unless you're connecting to very old systems that don't support it. RSA keys should be at least 4096 bits if you must use them.

Can I still use password auth for emergency access?
No. If you need a fallback, use console access from your hosting panel. Keeping password auth enabled "just in case" leaves the door open for attackers.

Does changing the SSH port break anything?
It breaks tools and scripts that assume port 22. Update your ~/.ssh/config file with the new port for each host, and make sure your firewall and fail2ban settings match.

How often should I rotate SSH keys?
Key rotation is less critical than protecting the keys you have. If a key is compromised or an employee leaves, rotate immediately. Otherwise, annual rotation is reasonable for high-security environments, but not strictly necessary if keys are well-protected.

Final verification steps

After applying these changes, test from a second terminal before closing your active session. Try logging in with a password (it should fail), verify key auth works on the new port, and confirm your user can sudo without issues. Check systemctl status sshd for any config errors, and review your firewall rules to ensure the new SSH port is open and the old one is closed.

These hardening steps have stopped every automated attack I've encountered in production. They take an hour to implement and eliminate the most common VPS compromise vectors. Your auth logs will go quiet, and your server will stop showing up in shodan scans as low-hanging fruit.