Short answer
- Secure SSH by replacing passwords with ed25519 keys and setting PasswordAuthentication no in sshd_config.
- Forbid direct root logins with PermitRootLogin no and work through a normal user that escalates with sudo.
- Restrict who can log in with AllowUsers, install fail2ban and, where you can, limit connection sources through a firewall or a VPN.
- Changing the port only reduces log noise and does not replace any of the measures above.
- Recommended key type
- ed25519
- Key settings in sshd_config
- PasswordAuthentication no, PermitRootLogin no
- PermitRootLogin default since OpenSSH 7.0
- prohibit-password
- Automatic blocking of repeated attempts
- fail2ban, sshd jail
Why keys beat any password
A password, however long, can be guessed, reused or phished. An ed25519 key never travels over the wire: the server checks a signature while the private half stays on your laptop, protected by a passphrase. Once password login is off, leaked password lists are useless. OpenSSH has refused root logins with a password by default since version 7.0, through prohibit-password, but the simplest rule is to ban root entirely and sign in with a personal account that escalates through sudo.
What fail2ban does and what it does not
fail2ban reads the authentication log and adds a temporary firewall rule for every IP that failed several times within a window. It stops slow brute force and cuts the noise. It does not protect you if password logins are still enabled on predictable accounts, because a botnet tries from thousands of IPs, once each. Order matters: keys and no root first, fail2ban as an extra layer. A non-standard port belongs in the same category, since scanning every port takes seconds.
- Add your own IPs to ignoreip so you do not lock yourself out
- Review authorized_keys regularly: an unknown key is the classic sign of a compromise
- Remove a colleague's key on the day they leave the team
Recommended sshd_config settings for a production server| Directive | Recommended value | What it does |
|---|
| PasswordAuthentication | no | Accepts keys only; password brute force becomes pointless |
|---|
| PermitRootLogin | no | Root cannot log in directly; you sign in as a user and use sudo |
|---|
| AllowUsers | deploy admin | Only the listed accounts can open sessions |
|---|
| MaxAuthTries | 3 | Limits attempts per connection |
|---|
| KbdInteractiveAuthentication | no | Closes the interactive password path as well |
|---|
Commands and configuration
Generate an ed25519 key and copy it to the serverssh-keygen -t ed25519 -a 100 -C "deploy@example.ro"
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@example.ro
/etc/ssh/sshd_config.d/10-hardening.conf (first check that sshd_config has the Include line; otherwise write straight into sshd_config)PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
AllowUsers deploy admin
MaxAuthTries 3
LoginGraceTime 30
fail2ban: /etc/fail2ban/jail.local[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1h
ignoreip = 127.0.0.1/8 203.0.113.10
Practical examples
SaaS team in Iasi, freshly installed VPS
In the first twelve hours after the IP was allocated, the log showed thousands of root login attempts from dozens of countries. With PasswordAuthentication no they all failed instantly, and fail2ban then shrank the log to a few lines a day.
Web agency in Timisoara working with freelancers
A former contractor still had a key in authorized_keys on five client servers a year after the contract ended. The agency introduced a central list of keys and a monthly check of the file on every machine it manages.
Common mistakes
- Treating a changed SSH port as security, when scanning all 65,535 ports takes seconds.
- Leaving PasswordAuthentication yes “just in case I lose the key”, which cancels the point of using keys.
- Sharing one key across the team with no passphrase, even saving it in the repository.
- Editing sshd_config and restarting without testing from a second session, then locking yourself out.
How 4hosting helps
- On VPS and dedicated servers you have root access and can apply the whole configuration above; Hardening & Compliance does it for you from the included hours: 1–8 on VPS, 5–10 on dedicated servers depending on the plan and 10 on GPU servers, requested from the client panel, in the “DevOps Services” section.
- VPN & WireGuard takes port 22 off the internet and exposes it only inside your private network.
- SIEM & Incident Response centralises the authentication logs and alerts on a new key in authorized_keys or a login from an unusual location.
Related questions
What if I lose my private key?
You need a second way in prepared beforehand: a second key kept offline, the console in the provider's panel, or KVM access on a dedicated server. That is why you do not leave passwords enabled as a backup; you use the provider console, which is not exposed to the internet.
Is it worth changing the SSH port?
Not as a security measure. It reduces log noise and bot load, which helps on a small server, but any scan finds the new port in seconds. If you want quiet, put SSH behind a VPN or restrict the source in the firewall.
Do I need 2FA for SSH if I use keys?
For most servers, keys with a passphrase are enough. On critical servers, or when many people have access, a TOTP second factor through PAM adds protection if a laptop is stolen with the key unlocked. Access only through a VPN has a similar effect.