A fresh VPS ships with SSH running on port 22, password authentication enabled, and root login wide open. That configuration is fine for the first five minutes while you're setting up keys. After that it's a liability.
I've seen brand-new Droplets and Lightsail instances get hammered with brute-force attempts within hours of spinning up. The auth logs fill with failed password guesses from botnets scanning IPv4 space. Most of those attacks fail because the root password is strong, but why leave the door ajar? A hardened SSH config stops the noise and closes off entire attack vectors before they matter.
This isn't about paranoia. It's about baseline hygiene every production VPS should have before you point a domain at it or run a live service.
Why default SSH settings are a problem
Out of the box, sshd allows password-based login for any user, including root. Attackers know this. Automated tools try common usernames and password lists against every public IP they find.
Password authentication has two flaws: humans pick weak passwords, and even strong passwords can be brute-forced given enough time and attempts. Key-based authentication solves both. An SSH key pair uses asymmetric cryptography, so there's nothing to guess. No dictionary attack will ever work.
Running SSH on port 22 also broadcasts "here's a Linux box; come try to log in." Changing the port doesn't make you invisible, but it does cut down on the automated scan traffic that clogs your logs and wastes CPU cycles on failed auth attempts. Think of it as moving your front door off the main street.
Root login over SSH is the third problem. Even if your root password is a 32-character random string, allowing direct root access means one compromised credential gives an attacker full control. Forcing users to log in as a non-privileged account and then sudo to root adds a layer of accountability and makes privilege escalation slightly harder.
Step one: create a non-root user with sudo access
Never do day-to-day admin work as root. Create a regular user and give it sudo privileges.
adduser deploy
usermod -aG sudo deploy
On CentOS or RHEL derivatives, replace sudo with wheel:
usermod -aG wheel deploy
Pick a username that isn't "admin" or "user" — those get targeted almost as often as root. I usually go with something tied to the service or team.
Test sudo access before you disable root login. Log in as the new user and run sudo whoami. It should print root. If it doesn't, check /etc/sudoers and make sure the sudo or wheel group is enabled.
Step two: set up SSH key authentication
Generate an SSH key pair on your local machine if you don't already have one. Ed25519 is the modern standard — faster and smaller than RSA.
ssh-keygen -t ed25519 -C "[email protected]"
You'll get two files: id_ed25519 (private key) and id_ed25519.pub (public key). The private key stays on your machine. The public key goes on the server.
Copy the public key to the server using ssh-copy-id:
ssh-copy-id deploy@your-server-ip
That appends your public key to ~/.ssh/authorized_keys on the server and sets the correct permissions. If ssh-copy-id isn't available, do it manually:
cat ~/.ssh/id_ed25519.pub | ssh deploy@your-server-ip "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
Then fix permissions on the server:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
Test the key login before you disable password auth. Open a new terminal and SSH in — it should let you in without asking for a password. If it prompts for a password, check the authorized_keys file and make sure the key is on one line with no extra whitespace.
Step three: disable password authentication and root login
Once key auth works, turn off password login. Edit /etc/ssh/sshd_config:
sudo nano /etc/ssh/sshd_config
Find and change these directives:
PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes
Some distros use KbdInteractiveAuthentication instead of ChallengeResponseAuthentication — set that to no as well if it's present.
Restart the SSH service:
sudo systemctl restart sshd
Do NOT close your current SSH session yet. Open a second terminal and try to SSH in with your key. If it works, great. If it doesn't, you still have the first session open to fix the config. I've locked myself out of a VPS exactly once by skipping this step. Don't be me.
Step four: change the default SSH port
Port 22 is a magnet for bot traffic. Moving SSH to a non-standard port won't stop a determined attacker, but it will stop the background noise.
Pick a port above 1024 and below 65535. Avoid common service ports like 8080, 3306, or 5432. I usually pick something random in the 40000–50000 range.
Edit /etc/ssh/sshd_config again and change the Port directive:
Port 45678
If you're running a firewall (you should be), open the new port before restarting SSH:
sudo ufw allow 45678/tcp
For firewalld:
sudo firewall-cmd --permanent --add-port=45678/tcp
sudo firewall-cmd --reload
Restart SSH:
sudo systemctl restart sshd
From now on, connect with:
ssh -p 45678 deploy@your-server-ip
Add the port to your ~/.ssh/config so you don't have to type it every time:
Host your-server
HostName your-server-ip
Port 45678
User deploy
Then you can just run ssh your-server.
Step five: install and configure fail2ban
Fail2ban watches log files for repeated failed login attempts and temporarily bans the offending IP. It's not a silver bullet — a slow, distributed attack will slip through — but it handles the bulk of automated brute-force traffic.
Install it:
sudo apt install fail2ban
On CentOS or RHEL, enable EPEL first:
sudo yum install epel-release
sudo yum install fail2ban
Fail2ban ships with a default config in /etc/fail2ban/jail.conf. Don't edit that file directly; it gets overwritten on upgrades. Instead, create /etc/fail2ban/jail.local and override the settings you care about:
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
port = 45678
Replace 45678 with whatever port you picked. The bantime, findtime, and maxretry values mean: ban an IP for one hour if it fails five login attempts within ten minutes.
Start and enable fail2ban:
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Check that the SSH jail is active:
sudo fail2ban-client status sshd
You'll see current ban counts and a list of banned IPs. After a few days, check back — you'll usually find a handful of addresses that tripped the threshold.
What about other SSH hardening tweaks?
There are more settings you can lock down, but they hit diminishing returns fast. Disabling X11 forwarding, setting MaxAuthTries to 3, or restricting AllowUsers to a specific list are all fine if your threat model calls for them. For most hosting scenarios, keys + fail2ban + a non-root user cover the realistic attack surface.
One setting worth mentioning: ClientAliveInterval and ClientAliveCountMax. These keep idle SSH sessions from timing out on flaky networks, but they also prevent dead connections from lingering. I set:
ClientAliveInterval 300
ClientAliveCountMax 2
That sends a keepalive every five minutes and disconnects after two missed responses. Adjust to taste.
Verifying your SSH hardening
After you've locked everything down, test from the outside. Try SSH-ing with a password — it should refuse. Try connecting as root — also refused. Check /var/log/auth.log (or /var/log/secure on RHEL) for failed login attempts and confirm fail2ban is catching repeat offenders.
Run sudo sshd -T to dump the active SSH config and verify your changes took effect. It's easy to typo a directive name or leave an old setting uncommented.
If you're using a VPS provider's web console, make sure you can still get in through that if SSH breaks. Some providers let you reset sshd_config from the console, but not all of them do.
Keeping SSH hardening up to date
SSH itself is stable and rarely needs config changes once it's locked down. What does need attention is keeping the SSH package updated. Check for security patches regularly:
sudo apt update && sudo apt upgrade openssh-server
On CentOS:
sudo yum update openssh-server
Subscribe to your distro's security mailing list or RSS feed so you hear about SSH vulnerabilities the day they drop, not three weeks later.
Common SSH hardening questions
Do I really need to change the SSH port?
No, but it drastically cuts log noise and pointless CPU burn from bot scans. Port obscurity isn't security, but it's free and it works.
Can I use password auth if I enable two-factor authentication?
Yes, 2FA mitigates the brute-force risk. But keys are simpler to manage and just as secure without the extra moving parts.
What if I lose my SSH key?
You'll need console access through your VPS provider's web interface to add a new key or temporarily re-enable password auth. Keep a backup of your private key in a password manager or encrypted volume.
Should I disable IPv6 SSH access?
Only if you're not using IPv6. Otherwise, attackers can just connect over v6 while you're watching v4 logs. If you disable it, set AddressFamily inet in sshd_config.
How often should I rotate SSH keys?
Unless a key is compromised, rotation is optional. Focus on protecting the private key with a strong passphrase and proper file permissions.
What to check first
If SSH stops working after hardening, the most common culprits are: firewall blocking the new port, authorized_keys file with wrong permissions, or a typo in sshd_config that prevents the daemon from starting. Check sudo systemctl status sshd for errors and review /var/log/auth.log for clues. Always keep a second session open until you've confirmed the new config works.
