← Back to Blog
Server Security · 16 min read · June 24, 2026

How to Secure SSH on Your Server in 2026

SSH is the front door to your server. If it is not locked properly, attackers will find it. This guide walks through every layer of SSH hardening — from key-based authentication to brute-force protection, port obfuscation, two-factor authentication, and continuous monitoring.

Reality check: A default SSH installation on port 22 with password authentication will be discovered and attacked within minutes of being exposed to the internet. Automated bots scan the entire IPv4 address space continuously. Securing SSH is not optional — it is the first thing you must do after provisioning any server.

Why SSH Is the Most Targeted Service on the Internet

SSH runs on every public-facing Linux server. It is the universal management interface. Attackers know this, and they have built an entire ecosystem of bots, scanners, and credential stuffers dedicated to breaking into SSH. Here is what that looks like in numbers:

The goal of this guide is to reduce that attack surface to near zero. By the end, your SSH service will be invisible to scanners, immune to brute-force attacks, and protected even if credentials are leaked.

Step 1: Use SSH Key Authentication (Disable Passwords)

Password-based SSH authentication is the single biggest security risk on most servers. It is vulnerable to brute-force attacks, credential stuffing, and credential theft. SSH key authentication uses asymmetric cryptography instead, making it exponentially harder to crack.

Generate a strong key pair

Use the Ed25519 algorithm — it is faster than RSA, more secure at shorter key lengths, and widely supported:

ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519

The -a 100 flag sets the number of KDF rounds to 100, making it harder to brute-force your private key if it is ever stolen. You will be prompted for a passphrase — use one. A strong passphrase protects your key even if your local machine is compromised.

Copy the public key to your server

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

This appends your public key to ~/.ssh/authorized_keys on the server. If ssh-copy-id is not available, append it manually:

cat ~/.ssh/id_ed25519.pub | ssh user@your-server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"

Disable password authentication in sshd_config

Once your key works, disable password authentication entirely:

sudo sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd

Verify by opening a second terminal session before closing the first one. A misconfigured SSH can lock you out. Always keep a backup session alive while testing.

Key point: With password authentication disabled and key-based authentication enabled, even if an attacker knows your username and has a billion-dollar password cracking rig, they cannot log in without your private key file.

Step 2: Disable Root Login Over SSH

Allowing direct root login via SSH is dangerous. Every brute-force bot on the internet tries the username root first. Disabling root login forces attackers to guess both a valid username and a password, dramatically increasing the difficulty.

sudo sed -i 's/^#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo systemctl restart sshd

Instead of logging in directly as root, connect with your regular user and use sudo for administrative tasks. This also provides an audit trail — every privileged command is logged with the originating username.

If you absolutely need occasional root SSH access (e.g., for automated deployment pipelines), use Match blocks in sshd_config to allow it only from specific IP addresses:

Match Address 203.0.113.0/24
    PermitRootLogin prohibit-password

Step 3: Change the Default SSH Port

Changing the SSH port from 22 to a high-numbered port is one of the most effective single changes you can make. Bots scan port 22 by default. Changing the port eliminates the vast majority of automated attack traffic immediately.

sudo sed -i 's/^#Port 22/Port 2222/' /etc/ssh/sshd_config
sudo sed -i 's/^Port 22/Port 2222/' /etc/ssh/sshd_config
sudo systemctl restart sshd

Choose a port above 1024 to avoid conflicts with well-known services. Popular alternatives include 2222, 10022, or 22222. Avoid obvious alternatives like 222 or 22222 that attackers might also check.

After changing the port, update your firewall rules and SSH client config:

# In your local ~/.ssh/config
Host my-server
    HostName your-server.com
    Port 2222
    User your-username
    IdentityFile ~/.ssh/id_ed25519

Do not forget to update your firewall to allow the new port:

sudo ufw allow 2222/tcp
sudo ufw delete allow 22/tcp

Security through obscurity: Changing the port alone is not a complete defense. It stops automated scanners that only check port 22, but a determined attacker can find your SSH port with a port scan. Combine port changing with the other measures in this guide for defense in depth.

Step 4: Install and Configure Fail2ban

Fail2ban monitors SSH authentication logs and temporarily bans IP addresses that show signs of brute-force attacks. It is the standard tool for blocking repeated failed login attempts at the network level.

# Install fail2ban
sudo apt update && sudo apt install fail2ban -y  # Debian/Ubuntu
sudo dnf install fail2ban -y                    # RHEL/Fedora

Create a local jail configuration for SSH:

sudo tee /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3

[sshd]
enabled = true
port = 2222
logpath = %(sshd_log)s
backend = %(sshd_backend)s
EOF

sudo systemctl restart fail2ban

This configuration bans an IP address for 1 hour after 3 failed login attempts within 10 minutes. Monitor bans with:

sudo fail2ban-client status sshd

On a public server, you will see banned IPs accumulate quickly. That is normal — it means fail2ban is doing its job.

Step 5: Restrict SSH by IP Address (Where Possible)

If you connect from a fixed IP address or a known range, restrict SSH access to those IPs only. This is the strongest possible SSH security measure because it blocks all traffic from outside your trusted network.

sudo ufw allow from 203.0.113.0/24 to any port 2222 proto tcp
sudo ufw deny 2222/tcp 2>/dev/null; sudo ufw --force enable

If you use a VPN, configure SSH to listen only on the VPN interface:

# In /etc/ssh/sshd_config
ListenAddress 10.8.0.1

For most users whose IP addresses change (home internet, mobile), a combination of key-based authentication, fail2ban, and port changing provides excellent protection without requiring a fixed IP.

Step 6: Enable Two-Factor Authentication for SSH

For the highest level of protection, add a second authentication factor. Even if an attacker steals your SSH private key, they would also need your one-time code to log in.

Install and configure the Google Authenticator PAM module

sudo apt install libpam-google-authenticator -y
google-authenticator

The google-authenticator command will:

Configure PAM and SSH to require the one-time code

# Edit /etc/pam.d/sshd
# Add this line at the top:
auth required pam_google_authenticator.so

# Edit /etc/ssh/sshd_config
sudo sed -i 's/^#ChallengeResponseAuthentication yes/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config
sudo sed -i 's/^ChallengeResponseAuthentication no/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config

# Require BOTH key AND 2FA
echo "AuthenticationMethods publickey,keyboard-interactive" | sudo tee -a /etc/ssh/sshd_config

sudo systemctl restart sshd

Now when you connect via SSH, you will need both your SSH key and a time-based one-time password from your authenticator app. This is defence in depth at its finest.

Pro tip: Save your Google Authenticator emergency scratch codes in a password manager before enabling 2FA. If you lose your phone and do not have the scratch codes, you will be permanently locked out of your server and will need console access to disable 2FA manually.

Step 7: Additional SSH Hardening Settings

Beyond the big changes above, several configuration options in /etc/ssh/sshd_config improve security:

# Limit users who can SSH
AllowUsers your-username deploy

# Limit authentication attempts per connection
MaxAuthTries 3

# Disable unused authentication methods
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication yes
KerberosAuthentication no
GSSAPIAuthentication no

# Disable X11 forwarding and agent tunneling if not needed
X11Forwarding no
AllowTcpForwarding yes   # Keep yes if you use SSH tunnels
AllowAgentForwarding no

# Use strong ciphers and key exchange algorithms
Ciphers [email protected],[email protected]
KexAlgorithms curve25519-sha256,diffie-hellman-group16-sha512
MACs [email protected],[email protected]

# Idle timeout — disconnect inactive sessions
ClientAliveInterval 300
ClientAliveCountMax 2

After making all changes, always reload and test:

sudo sshd -t                    # Syntax check
sudo systemctl restart sshd     # Apply changes

Step 8: Auditing and Monitoring SSH Access

Hardening SSH is not a one-time task. You need to monitor access logs and detect anomalies continuously.

Check authentication logs regularly

Failed login attempts and unusual access patterns should be reviewed:

# Recent successful logins
sudo grep "Accepted " /var/log/auth.log | tail -20

# Failed login attempts
sudo grep "Failed password" /var/log/auth.log | tail -20

# Show unique IPs that tried to connect
sudo zgrep "Failed password" /var/log/auth.log* | grep -oP 'from \K[0-9.]+' | sort | uniq -c | sort -rn | head -20

Monitor for SSH key changes

# Check if authorized_keys has been modified
sudo stat /home/*/.ssh/authorized_keys
# Watch for changes in real time
sudo inotifywait -m /home/*/.ssh/

Automated monitoring

Manual log checking is unreliable for ongoing protection. A system that continuously monitors SSH authentication patterns, failed login spikes, and unusual geographic origins catches attacks in real time. RootCrak's AI Watchdog tracks SSH authentication events as part of its continuous security monitoring — it detects brute-force attacks, credential stuffing campaigns, and anomalous login patterns within seconds.

The Complete SSH Hardening Checklist

Use this as your go-to checklist when provisioning any new server:

  1. Generate Ed25519 keys — use ssh-keygen -t ed25519 -a 100
  2. Disable password authentication — set PasswordAuthentication no
  3. Disable root login — set PermitRootLogin no
  4. Change the default port — move off port 22 to a high port
  5. Install fail2ban — ban IPs after 3 failed attempts
  6. Restrict by IP — use UFW or iptables if you have a fixed IP
  7. Enable 2FA — add Google Authenticator PAM module
  8. Harden cipher config — use only strong ciphers and MACs
  9. Set idle timeout — disconnect inactive sessions automatically
  10. Audit logs regularly — review auth.log for anomalies
  11. Set up automated monitoring — detect attacks in real time

Bottom line: A properly hardened SSH configuration stops 99.9 percent of automated attacks. The combination of key-based authentication, port changing, fail2ban, and IP whitelisting makes your server effectively invisible to the bot networks that constantly scan the internet.

Frequently Asked Questions

How do I secure SSH on my Linux server?

Start with these essential steps: disable password authentication and use SSH keys instead, disable root login via PermitRootLogin no, change the default port 22 to a non-standard port, install and configure fail2ban to block brute-force attempts, and set up a firewall to restrict SSH access to trusted IPs where possible.

Should I change the default SSH port from 22?

Yes, changing the default SSH port from 22 to a high-numbered port (e.g. 2222 or 10022) significantly reduces automated brute-force attacks. Bots scan port 22 by default. Changing the port eliminates 99 percent of automated scan traffic. Combine this with key-based authentication and fail2ban for maximum protection.

How do I use SSH key authentication instead of passwords?

Generate a key pair on your local machine using ssh-keygen -t ed25519 -a 100, then copy the public key to your server using ssh-copy-id user@your-server. Edit /etc/ssh/sshd_config and set PasswordAuthentication no, then restart SSH with systemctl restart sshd. Always keep your private key secure and protected with a strong passphrase.

What is fail2ban and how does it protect SSH?

Fail2ban is a log-parsing intrusion prevention tool that monitors SSH authentication logs for repeated failed login attempts. After a configurable number of failures (default is 5), it temporarily bans the offending IP address using iptables or nftables. This stops brute-force attacks at the network level before they can try thousands of passwords.

How do I enable two-factor authentication for SSH?

Install the google-authenticator-libpam package on your server, run google-authenticator to generate a secret and recovery codes, then edit /etc/pam.d/sshd to add the PAM module. In /etc/ssh/sshd_config, set ChallengeResponseAuthentication yes and AuthenticationMethods publickey,keyboard-interactive. This requires both an SSH key and a one-time code from your authenticator app to log in.

Hardening takes time. Monitoring is automatic.

RootCrak's AI Watchdog continuously monitors SSH authentication patterns, scans for open ports, and alerts you to brute-force attacks in real time. Get a free audit and see your security score in under 90 seconds.

Start Free Audit