Published 2026-09-08 · Updated 2026-10-22
SSH Hardening: Best Practices to Stop Brute-Force Attacks
SSH hardening means restricting how your server accepts remote logins so that automated brute-force scripts and credential-stuffing bots cannot get in, even if they run for years. The core steps are: switch to key-based authentication, disable root login and password login, restrict which accounts and networks can connect, and pair sshd with a firewall and an intrusion-prevention tool like fail2ban. This guide walks through each step with the actual configuration lines to use.
In this guide
Why SSH is the top target on a new server Switch to key-based authentication Disable root login over SSH Should you change the default SSH port? Restrict who can connect Harden sshd_config: the full checklist Modern ciphers, key exchange, and MACs Rate-limit login attempts with fail2ban Put SSH behind a firewall Frequently asked questionsQuick win: do this in the next 10 minutes
- Generate an Ed25519 key pair on your workstation and copy the public key to the server's
authorized_keysfile. - Confirm you can log in with the key in a second terminal window before touching anything else.
- Set
PermitRootLogin noandPasswordAuthentication noin/etc/ssh/sshd_config. - Run
sudo sshd -tto validate the config, thensudo systemctl reload sshd. - Keep your original session open until the new login is confirmed working, so you don't lock yourself out.
Why SSH is the top target on a new server
Any internet-facing Linux server with SSH open on port 22 will start receiving automated login attempts within minutes of coming online. Credential attacks remain one of the dominant ways attackers get an initial foothold: the 2025 Verizon Data Breach Investigations Report found stolen credentials were involved in roughly 32% of breaches overall, and used as the initial access vector in about 22% of breaches, with credential abuse the dominant tactic behind basic web application attacks. For a small or mid-sized business running its own VPS, this shows up as a constant stream of failed login attempts against SSH from botnets scanning the entire IPv4 address space for weak or default credentials.
The good news is that SSH hardening is one of the highest-leverage security investments you can make on a server. Unlike patching a specific application vulnerability, hardening SSH closes off an entire class of automated attacks in one sitting, and most of the changes take minutes to apply.
Switch to key-based authentication
Key-based authentication replaces a guessable password with a cryptographic key pair, which makes brute-forcing your way in computationally infeasible. This is the single most important SSH hardening step, and everything else in this guide builds on it.
Generate a key pair with a modern algorithm. Ed25519 is the recommended default for new keys: it uses a 256-bit key to reach a security level comparable to a 3072-bit RSA key, it is fast to compute, and its signatures are deterministic, which removes a class of nonce-reuse bugs that has affected some RSA and ECDSA implementations. If you need compatibility with older systems that predate OpenSSH 6.5 (roughly pre-2014), fall back to RSA at 4096 bits. Never generate or accept a 1024-bit or 2048-bit RSA key for anything internet-facing today.
ssh-keygen -t ed25519 -C "you@example.com"
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server-ip
Protect the private key with a passphrase, and never copy a private key onto the server itself. Once you've confirmed key-based login works in a separate terminal session, you can safely disable password authentication in sshd_config:
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey
Keep that first working session open while you test the new configuration. If something is misconfigured, you can revert it from the still-open session instead of getting locked out.
Disable root login over SSH
Root should never be allowed to log in directly over SSH, because it removes the audit trail of which individual account performed an action and gives an attacker who guesses or steals one credential immediate full control. Set PermitRootLogin no in sshd_config and use sudo from a named account instead.
PermitRootLogin no
If you have automation that currently depends on root login, create a dedicated service account with a restricted, key-only login and grant it exactly the sudo privileges it needs through /etc/sudoers.d/, rather than reinstating root access.
Should you change the default SSH port?
Moving SSH off port 22 does not make your server more secure against a targeted attacker, but it does dramatically cut the volume of noise from opportunistic, internet-wide scanners in your logs. Treat it as a minor operational convenience, not a security control, and never let it substitute for key-based authentication, firewall rules, or fail2ban.
If you do change the port, pick something above 1024, update your firewall rule to match, and document the new port clearly for anyone else on your team, since a forgotten non-standard port is a common cause of unnecessary support tickets.
Port 2222
Restrict who can connect
Limiting SSH access to specific accounts, groups, and source networks shrinks the attack surface even further, because an attacker with a stolen key for the wrong user, or a connection from the wrong network, is rejected before authentication is even attempted. Use AllowUsers or AllowGroups to name exactly who is permitted:
AllowUsers deploy admin
AllowGroups ssh-users
If your team connects from a known office IP range, a VPN, or a bastion host, layer that restriction into your firewall as well (see the section on firewalls below). This means a stolen or leaked key is useless to an attacker connecting from an unrecognized network.
Harden sshd_config: the full checklist
Beyond authentication and access control, a handful of additional sshd_config directives close off forwarding tricks, tighten timeouts, and reduce the information an unauthenticated connection can extract. These settings are consistent with CIS Benchmark guidance for Linux SSH hardening and are safe defaults for most VPS workloads:
Protocol 2
LoginGraceTime 30
MaxAuthTries 3
MaxSessions 4
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
GatewayPorts no
PermitTunnel no
PermitEmptyPasswords no
IgnoreRhosts yes
HostbasedAuthentication no
PrintMotd no
LogLevel VERBOSE
LoginGraceTime limits how long an unauthenticated connection can sit open, and MaxAuthTries caps how many authentication attempts a single connection gets, both of which reduce the window a scripted attack has to work with. ClientAliveInterval and ClientAliveCountMax together disconnect idle or dead sessions automatically. Disabling X11, TCP, and agent forwarding closes off tunneling techniques that are rarely needed on a production server and are sometimes abused to pivot deeper into a network. LogLevel VERBOSE ensures the key fingerprint is logged for every login attempt, which is valuable if you ever need to investigate a breach (see our guide to detecting and responding to a server breach).
After editing /etc/ssh/sshd_config, always validate the syntax before reloading:
sudo sshd -t
sudo systemctl reload sshd
Want a second pair of eyes on your SSH config?
Get a free, read-only server security check that reviews your SSH, firewall, and patch posture, or talk to a security engineer about managed protection.
Get your free server check Talk to a security engineerModern ciphers, key exchange, and MACs
Restricting sshd to modern cipher suites and key exchange algorithms closes off legacy cryptography that is either weak or deprecated, without breaking compatibility with any client from the last several years. Mozilla's OpenSSH guidelines, widely used as a baseline for hardened configurations, recommend the following for current OpenSSH versions:
KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
Curve25519 is generally preferred over the NIST P-curves for key exchange, and the NIST curves are listed mainly for compatibility with older clients. Avoid CBC-mode ciphers and MD5 or SHA-1 based MACs entirely; they have known weaknesses and modern OpenSSH clients rarely need them. You can audit your current configuration against these recommendations with a tool like ssh-audit, which flags any weak algorithm still enabled on your server.
Rate-limit login attempts with fail2ban
Fail2ban watches your authentication logs and automatically bans IP addresses that generate too many failed login attempts in a short window, which stops distributed brute-force attempts from grinding away indefinitely even if a stray password login is ever re-enabled. A typical sshd jail configuration in /etc/fail2ban/jail.local looks like this:
[sshd]
enabled = true
port = ssh
maxretry = 3
findtime = 10m
bantime = 1h
bantime.increment = true
findtime is the window in which failed attempts are counted, maxretry is how many failures within that window trigger a ban, and bantime is how long the ban lasts. Enabling bantime.increment makes repeat offenders get progressively longer bans, which is effective against botnets that retry from the same address after a short cooldown. We cover jail tuning, whitelisting, and integration with other services in the Fail2ban setup guide.
Put SSH behind a firewall
A firewall rule that only allows SSH traffic from known networks adds a layer that works even if a key or password were somehow compromised, because the connection is rejected at the network level before SSH ever processes it. On Ubuntu or Debian, ufw is the simplest way to enforce a default-deny policy while explicitly allowing SSH:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable
If your team connects from a fixed office IP or VPN exit node, restrict the rule further with ufw allow from <ip> to any port 22. For more control, or if you are managing multiple servers with more complex rule sets, nftables is the modern successor to iptables and is worth learning. We compare all three approaches, including when to reach for nftables over ufw, in the Linux firewall guide: iptables vs nftables vs ufw.
SSH hardening is one piece of a broader server security posture. For the full picture, including patching, monitoring, and DDoS protection, see the VPS security checklist: the complete guide. If you inherited a server that has never been hardened, that checklist is a good starting point before you dive into the details above.
In the news: CVE-2026-35414 shows what happens when an SSH authentication mechanism itself has a flaw, a good reminder to keep OpenSSH current alongside the configuration hardening covered here.
Next steps: once key authentication is in place, add a second factor with the SSH two-factor authentication guide, and limit what logged-in accounts can do with users, sudo and least privilege.
Directive references: PermitRootLogin, PasswordAuthentication, MaxAuthTries and AllowUsers each have a short reference with accepted values and how to test them safely; for reaching internal hosts, see bastion host.
Related guides: how to stop SSH brute-force attacks, SSH "Permission denied (publickey)" fixes, recovering from an SSH lockout.
Frequently asked questions
Should I change the default SSH port from 22?
Changing the SSH port is not a real security control, but it does cut down the volume of automated scans hitting your logs. Use it as a minor convenience on top of key-based authentication and a firewall, never as a substitute for them.
Is disabling password authentication enough on its own?
Disabling password authentication removes the most common brute-force target, but it should be combined with disabling root login, restricting which accounts can connect over SSH, and rate-limiting connection attempts with a tool like fail2ban.
What SSH key type should I use in 2026?
Ed25519 is the recommended default for new SSH keys. It offers strong security with a much smaller key size than RSA. If you need to support legacy systems that cannot use Ed25519, use RSA at 4096 bits, never 1024 or 2048.
Does fail2ban replace the need for key-based authentication?
No. Fail2ban slows down and blocks brute-force attempts by banning IPs after repeated failures, but it works best as a second layer behind key-based authentication and a properly configured firewall, not as a replacement for either.
How often should I rotate SSH keys?
There is no fixed schedule that fits every environment. Rotate a key immediately if a laptop is lost or an employee leaves, and review the authorized_keys files on your servers periodically to remove access that is no longer needed.
Can I use SSH certificates instead of individual keys?
Yes. OpenSSH supports a certificate authority model where a trusted CA signs short-lived user and host certificates. This scales better than distributing individual public keys across many servers and makes revocation simpler, though it requires more setup.
What is the difference between LoginGraceTime and MaxAuthTries?
LoginGraceTime limits how long an unauthenticated connection can stay open before the server drops it. MaxAuthTries limits how many authentication attempts a single connection can make. Both reduce the window an attacker has to work with.
Not sure where your server stands?
Get a free, read-only security check, or talk to a security engineer about managed protection.
Get your free server check Talk to a security engineer