AI News Hub Logo

AI News Hub

SSH Hardening — The Ultimate Guide for 2026

DEV Community
byteguard

SSH Hardening — The Ultimate Guide for 2026 If your server has a public IP, it's getting SSH brute-force attempts right now. Not maybe. Not eventually. Right now. Check your auth log: grep "Failed password" /var/log/auth.log | tail -20 You'll see hundreds — sometimes thousands — of failed login attempts from IPs you've never seen. Botnets scan the entire IPv4 space and hammer port 22 with common username/password combinations 24/7. My basic VPS hardening guide covers the essentials. This SSH hardening guide goes deeper — every sshd_config setting that matters, key-based authentication, two-factor auth, and monitoring. By the end, your SSH setup will be hardened against everything from automated bots to targeted attacks. A Linux VPS (Ubuntu 22.04/24.04 or Debian 12) with root or sudo access SSH access already working (don't lock yourself out before setting up alternatives) A second terminal/session open as a safety net while making changes Warning: Always keep a second SSH session open when modifying SSH config. If you make a mistake, the existing session stays connected. Test your new config in a new connection before closing the old one. Password authentication is the weakest link. Even a strong password can be brute-forced given enough time. SSH keys are cryptographically stronger and immune to dictionary attacks. ssh-keygen -t ed25519 -C "[email protected]" Ed25519 is the modern default — faster and more secure than RSA. If you need RSA compatibility (some older systems), use: ssh-keygen -t rsa -b 4096 -C "[email protected]" You'll be prompted for a passphrase. Use one. The passphrase encrypts the private key on disk. If someone steals your key file, the passphrase is the last line of defense. ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server-ip Or manually: cat ~/.ssh/id_ed25519.pub | ssh user@your-server-ip "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys" Open a new terminal (keep the old one open) and test: ssh user@your-server-ip If it logs in without asking for a password (or asks for your key passphrase instead), key auth is working. The main SSH server config lives at /etc/ssh/sshd_config. Every change below goes in this file. After editing, restart SSH to apply: sudo systemctl restart sshd Once key-based auth works, disable passwords entirely: PasswordAuthentication no This single change eliminates brute-force password attacks completely. Bots can hammer port 22 all day — without the private key, they're not getting in. PermitRootLogin no Even with key auth, there's no reason to allow direct root login. Use a regular user and sudo for privilege escalation. This adds a layer — an attacker needs both the SSH key and knowledge of which user has sudo access. Port 2222 Changing from port 22 won't stop a determined attacker, but it eliminates 99% of automated bot traffic. Most botnets only scan port 22. This is security through obscurity — not a defense by itself, but it reduces noise in your logs dramatically. After changing the port, update your firewall: sudo ufw allow 2222/tcp comment "SSH custom port" sudo ufw delete allow 22/tcp And connect with: ssh -p 2222 user@your-server-ip PermitEmptyPasswords no This should already be the default, but explicitly set it. MaxAuthTries 3 After 3 failed attempts, the connection is dropped. Combined with Fail2Ban, this makes brute-force attacks impractical. LoginGraceTime 30 The server waits 30 seconds for authentication before disconnecting. The default is 120 seconds — that's too generous. Reduce it to limit resource consumption from idle connections. X11Forwarding no Unless you're running graphical applications over SSH (unlikely on a server), disable this. It's an unnecessary attack surface. AllowTcpForwarding no If you don't use SSH tunnels, disable forwarding. If you use SSH tunnels for things like database access, leave it enabled or restrict to specific users. AllowUsers yourusername This is a whitelist. Only the listed users can log in via SSH. Everyone else is rejected before authentication even starts. KexAlgorithms curve25519-sha256,[email protected] Ciphers [email protected],[email protected],[email protected] MACs [email protected],[email protected] HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256 This disables weak algorithms (3DES, SHA1, diffie-hellman-group1). Modern clients support all of these. If you have very old clients that can't connect after this change, they need upgrading — not your server weakening its crypto. Here's the full set of changes in one block. Add or modify these lines in /etc/ssh/sshd_config: # Network Port 2222 AddressFamily inet # IPv4 only (set to 'any' if you use IPv6) ListenAddress 0.0.0.0 # Authentication PermitRootLogin no PasswordAuthentication no PermitEmptyPasswords no PubkeyAuthentication yes AuthenticationMethods publickey MaxAuthTries 3 LoginGraceTime 30 # Access control AllowUsers yourusername # Security X11Forwarding no AllowTcpForwarding no AllowAgentForwarding no PermitTunnel no # Crypto KexAlgorithms curve25519-sha256,[email protected] Ciphers [email protected],[email protected],[email protected] MACs [email protected],[email protected] HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256 # Logging LogLevel VERBOSE # Misc ClientAliveInterval 300 ClientAliveCountMax 2 MaxSessions 3 Banner none Validate the config before restarting: sudo sshd -t If there are no errors, restart: sudo systemctl restart sshd Test in a new terminal before closing your current session. Fail2Ban monitors your auth logs and temporarily bans IPs that fail authentication too many times. Even with key-based auth, it reduces log noise and blocks scanners. Install Fail2Ban: sudo apt update && sudo apt install fail2ban -y Create a local config (don't edit the main config — it gets overwritten on updates): sudo tee /etc/fail2ban/jail.local /dev/null fi Make it executable: sudo chmod +x /etc/profile.d/ssh-notify.sh This sends you an email every time someone logs in via SSH. If you see a login you don't recognize, investigate immediately. Key rotation. Rotate your SSH keys annually. Generate a new pair, add the new public key, verify it works, then remove the old one from authorized_keys. Agent forwarding risks. If you enable SSH agent forwarding (-A), anyone with root on the intermediate server can use your agent to authenticate to other servers. Use ProxyJump instead of agent forwarding where possible. Authorized keys audit. Periodically check ~/.ssh/authorized_keys on all users. Remove any keys you don't recognize. SSH config on the client side. Create ~/.ssh/config entries for your servers to avoid typing ports and usernames: Host byteguard HostName your-server-ip User yourusername Port 2222 IdentityFile ~/.ssh/id_ed25519 Then connect with ssh byteguard. Problem: Locked out after disabling password auth. PasswordAuthentication yes, restart SSH, and fix your key setup. Problem: Connection refused after changing the port. ufw status, and ensure the new port is allowed. Verify sshd_config has the right port. Problem: "Too many authentication failures" error. ssh -i ~/.ssh/id_ed25519 -p 2222 user@server. Or set IdentitiesOnly yes in your SSH client config. Problem: 2FA prompt doesn't appear. sshd_config not updated. auth required pam_google_authenticator.so is in /etc/pam.d/sshd. Verify ChallengeResponseAuthentication yes and AuthenticationMethods publickey,keyboard-interactive in sshd_config. Restart SSH. Problem: Fail2Ban not banning IPs. sudo fail2ban-client status sshd for errors. Verify logpath matches your system (/var/log/auth.log on Ubuntu/Debian). Verify the port matches your custom SSH port. SSH is the front door to your server. Every hardening step here stacks — key-based auth eliminates password attacks, Fail2Ban blocks scanners, a custom port reduces noise, and 2FA adds a second factor even if your key is compromised. If you haven't done the basics yet, start with my VPS hardening guide — it covers UFW, unattended upgrades, and user setup alongside basic SSH config. For protecting other services, check out the Fail2Ban setup guide and Docker security best practices. Your server is only as secure as its weakest entry point. Make SSH a strong one.