Imagine handing out thousands of copies of your house key to strangers and hoping none of them try to break in. That’s exactly what running SSH with default settings feels like. Every botnet, script kiddie, and sophisticated attacker is constantly scanning the internet for open SSH ports, trying to brute-force their way into your server.
SSH (Secure Shell) is the gateway to your Ubuntu server—and in 2026, it’s the primary target for cyberattacks. With credential stuffing attacks increasing by 300% year-over-year, securing SSH is no longer optional; it’s your first line of defense.
In this comprehensive guide, we’ll walk through proven SSH hardening techniques that will dramatically reduce your attack surface and protect your Ubuntu servers from unauthorized access.
Why SSH Security Matters
SSH is your most critical service. Here’s why:
- Root Access: A compromised SSH key means complete server takeover.
- Persistent Attacks: Automated bots attempt billions of SSH logins daily.
- Data Breaches: Over 80% of data breaches involve compromised credentials.
- Compliance: Standards like PCI-DSS, HIPAA, and GDPR require strong SSH security.
Prerequisites
Before we begin:
- Ubuntu 20.04 LTS or newer
- Root or sudo access
- Basic command-line knowledge
- Backup access method (console or out-of-band management)
Step 1: Initial Hardening - Core Configuration
The /etc/ssh/sshd_config file controls SSH behavior. Let’s harden it properly.
Backup Your Configuration
Always backup before making changes:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.$(date +%Y%m%d)
Essential Security Settings
Edit the SSH configuration:
sudo nano /etc/ssh/sshd_config
Apply these critical settings:
# Disable root login (absolutely essential!)
PermitRootLogin no
# Disable password authentication (use keys only)
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
# Enable public key authentication
PubkeyAuthentication yes
# Change default SSH port (reduces automated attacks)
Port 2222 # Choose any port > 1024
# Limit login attempts
MaxAuthTries 3
MaxSessions 2
# Idle timeout (disconnects inactive sessions)
ClientAliveInterval 300
ClientAliveCountMax 0
# Display last login
PrintLastLog yes
# Protocol version (use only SSHv2)
Protocol 2
# Reject empty passwords
PermitEmptyPasswords no
# Allow only specific users (optional but recommended)
AllowUsers yourusername adminuser
# Restrict which IPs can connect (optional)
# ListenAddress 192.168.1.100
# Log SSH activity
LogLevel VERBOSE
# Disable X11 forwarding unless needed
X11Forwarding no
# Disable agent forwarding
AllowAgentForwarding no
AllowTcpForwarding no
# Disable .rhosts files
IgnoreRhosts yes
# Disable host-based authentication
HostbasedAuthentication no
# Strict modes for .ssh directory
StrictModes yes
Apply Changes
# Test configuration syntax
sudo sshd -t
# If no errors, restart SSH
sudo systemctl restart sshd
Warning: If you changed the SSH port, don’t close your current session until you test connectivity from a new terminal!
Step 2: SSH Key Authentication
Password authentication is vulnerable. SSH keys are the gold standard.
Generate SSH Key Pair (Local Machine)
On your local computer:
# Generate ed25519 key (faster and more secure than RSA)
ssh-keygen -t ed25519 -C "your_email@example.com"
# Or use RSA 4096-bit (legacy compatibility)
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
Copy Public Key to Server
Method 1: Using ssh-copy-id
ssh-copy-id -i ~/.ssh/id_ed25519.pub username@your-server-ip -p 2222
Method 2: Manual Method
# On local machine
cat ~/.ssh/id_ed25519.pub
# On server, paste into authorized_keys
mkdir -p ~/.ssh
echo "ssh-ed25519 AAAAC3... your_key_here" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh
Test Key Authentication
# Test connection with key
ssh -i ~/.ssh/id_ed25519 username@your-server-ip -p 2222
# If successful, disable password authentication in sshd_config
sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
Step 3: Implement Fail2ban
Fail2ban blocks IPs after repeated failed login attempts. For a complete deep-dive setup, see our Fail2Ban Setup & Configuration guide.
Install Fail2ban
sudo apt update
sudo apt install fail2ban -y
Configure Jail for SSH
Create a custom configuration:
sudo nano /etc/fail2ban/jail.local
Add this configuration:
[sshd]
enabled = true
port = 2222 # Change to your SSH port
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600 # Ban for 1 hour
findtime = 600 # Count attempts over 10 minutes
ignoreip = 127.0.0.1/8 ::1 # Whitelist localhost
Configure SSH Filter (Optional)
Create custom filter for better detection:
sudo nano /etc/fail2ban/filter.d/sshd-custom.conf
[Definition]
failregex = ^.*Failed password for .* from <HOST> port .* ssh2$
^.*Connection closed by authenticating user .* from <HOST>$
^.*Received disconnect from <HOST>: .*: Bye Bye$
^.*Connection reset by peer from <HOST>$
ignoreregex =
Start and Enable Fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# Check status
sudo fail2ban-client status sshd
# Check banned IPs
sudo fail2ban-client status sshd | grep "Banned IP list"
Monitoring Fail2ban
# View live log
sudo tail -f /var/log/fail2ban.log
# Unban an IP
sudo fail2ban-client set sshd unbanip 192.168.1.100
Step 4: Advanced SSH Hardening
Use Hardware Security Keys (FIDO2/U2F)
Ubuntu 22.04+ supports FIDO2 keys with sk-ecdsa-sha2-nistp256:
# Generate key with hardware token
ssh-keygen -t ecdsa-sk -O resident -O verify-required
# Copy public key to server
ssh-copy-id -i ~/.ssh/id_ecdsa_sk.pub username@server
Set Up SSH Certificate Authentication
For enterprise environments, SSH certificates provide centralized management:
# On CA server, create certificate
ssh-keygen -t ed25519 -f ~/.ssh/ca-key
# On client, sign certificate
ssh-keygen -s ~/.ssh/ca-key -I user-001 -n yourusername -V +52w user-key.pub
# On SSH server, add CA public key to sshd_config
TrustedUserCAKeys /etc/ssh/ca-key.pub
Use Socket Activation (Ubuntu 24.04+)
Reduces attack surface by listening only when needed:
sudo systemctl edit sshd.socket
Add:
[Socket]
ListenStream=2222
Accept=yes
FreeBind=true
Configure SSH for Two-Factor Authentication
Add an extra layer with Google Authenticator:
# Install PAM module
sudo apt install libpam-google-authenticator -y
# Run setup for your user
google-authenticator
# Enable PAM in /etc/pam.d/sshd
# Add at top:
# auth required pam_google_authenticator.so
# In /etc/ssh/sshd_config:
# ChallengeResponseAuthentication yes
# AuthenticationMethods publickey,keyboard-interactive
Step 5: Network-Level Protections
Restrict SSH Access by IP
# Allow only specific IPs in /etc/hosts.allow
sudo nano /etc/hosts.allow
Add:
sshd: 192.168.1.0/24, 10.0.0.5, .domain.com
sshd: ALL: deny
Use UFW to Restrict Access
# Remove default SSH port if changed
sudo ufw delete allow ssh
# Add new SSH port with rate limiting
sudo ufw limit 2222/tcp
# Apply
sudo ufw reload
Port Knocking (Advanced)
Port knocking hides SSH until a specific sequence is sent:
# Install knockd
sudo apt install knockd -y
# Configure /etc/knockd.conf
[options]
LogFile = /var/log/knockd.log
[SSH]
sequence = 7000,8000,9000
seq_timeout = 5
command = /sbin/iptables -A INPUT -s %IP% -p tcp --dport 2222 -j ACCEPT
tcpflags = syn
# Start knockd
sudo systemctl enable knockd
sudo systemctl start knockd
Step 6: Monitoring and Auditing
Implement SSH Audit Logs
Create detailed SSH logging:
# Enable ssh-audit logging
sudo nano /etc/ssh/sshd_config
Add:
# Detailed logging
LogLevel VERBOSE
# Log all commands (for auditing)
ForceCommand /usr/bin/script -q -c "/bin/bash" /var/log/ssh-sessions/$$.log
Set Up SSH Session Recording
Record all SSH sessions for compliance:
# Install session recording
sudo apt install tlog -y
# Configure tlog in /etc/sssd/sssd.conf
# [domain/yourdomain]
# session_provider = tlog
# Enable in /etc/tlog/tlog-rec-session.conf
sudo tlog-rec-session
Regular Security Audits
# Check SSH configuration
sudo ssh-audit localhost
# Scan for vulnerable ciphers
nmap --script ssh2-enum-algos -p 2222 your-server
# Check for unused SSH keys
find /home -name "authorized_keys" -exec wc -l {} \;
# Check SSH history
sudo grep "sshd" /var/log/auth.log | grep -i "Accepted"
Step 7: Automatic Updates and Maintenance
Configure Automatic Security Updates
# Install unattended-upgrades
sudo apt install unattended-upgrades -y
# Configure
sudo dpkg-reconfigure --priority=low unattended-upgrades
# Add SSH to auto-update list
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
Add:
Unattended-Upgrade::Package-Blacklist {
// Remove SSH from blacklist
};
Regular SSH Key Rotation
Create a script to rotate keys:
#!/bin/bash
# rotate-ssh-keys.sh
# Backup current keys
sudo mkdir -p /root/ssh-backups/$(date +%Y%m%d)
sudo cp -r /etc/ssh/ssh_host_* /root/ssh-backups/$(date +%Y%m%d)
# Generate new host keys
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
sudo ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""
# Restart SSH
sudo systemctl restart sshd
# Notify users about key change
echo "SSH host keys rotated on $(date)" | mail -s "SSH Key Rotation" admin@yourdomain.com
Real-World Security Scenario: Server Hardening Checklist
Development Server
# Basic hardening
sudo sed -i 's/Port 22/Port 2222/' /etc/ssh/sshd_config
sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# Setup fail2ban
sudo apt install fail2ban -y
sudo systemctl enable fail2ban --now
# Add your key
ssh-copy-id user@server -p 2222
Production Server
# Enterprise-level hardening
sudo ./ssh-hardening.sh
# Features:
# - Two-factor authentication enabled
# - IP whitelisting
# - Rate limiting
# - Session recording
# - HIDS integration (Wazuh/Auditd)
# - IDS/IPS monitoring
# - Automated key rotation
Troubleshooting SSH Issues
Issue 1: Connection Refused
# Check if SSH is running
sudo systemctl status sshd
# Check if port is listening
sudo netstat -tlnp | grep 2222
# Check firewall
sudo ufw status
Issue 2: Permission Denied (Publickey)
# Check file permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
# Verify authorized_keys content
cat ~/.ssh/authorized_keys
# Check SSH verbose output
ssh -vvv user@server -p 2222
Issue 3: “Too many authentication failures”
# Disconnect session
sudo pkill -u username
# Reset fail2ban ban
sudo fail2ban-client set sshd unbanip your-ip
# Clear auth failures
echo > /var/log/auth.log # Be careful with this!
Emergency Recovery
If you get locked out:
# Access via console/VNC
# Restore backup configuration
sudo cp /etc/ssh/sshd_config.backup /etc/ssh/sshd_config
sudo systemctl restart sshd
# Temporarily enable password auth
sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# Set temporary permit root
sudo sed -i 's/PermitRootLogin no/PermitRootLogin yes/' /etc/ssh/sshd_config
sudo systemctl restart sshd
Conclusion
Securing SSH on Ubuntu is not a one-time task—it’s an ongoing process that requires vigilance, regular updates, and continuous monitoring. In 2026, with sophisticated cyberattacks becoming more common, these security measures are essential for protecting your servers.
Key Takeaways:
- Always disable root login
- Use SSH keys exclusively (no passwords)
- Implement fail2ban for automatic threat blocking
- Change default port to reduce automated attacks
- Use multi-factor authentication for critical systems
- Monitor logs and conduct regular security audits
- Keep SSH updated with security patches
Remember: Security is about layers. No single measure is foolproof, but combining multiple defenses creates a robust barrier against unauthorized access.
Ready for more security? Explore our Complete Ubuntu Server Security Guide.
Frequently Asked Questions (FAQs)
Q: Can I use both password and key authentication?
A: Yes, but it’s not recommended. Use AuthenticationMethods publickey,password for two-factor authentication, but relying solely on passwords is risky.
Q: How often should I rotate SSH keys? A: Rotate user keys every 3-6 months. Rotate host keys annually or when there’s a security concern.
Q: Is Ed25519 better than RSA? A: Yes. Ed25519 offers better security and performance than RSA-2048 and RSA-4096. Use it unless you need legacy compatibility.
Q: What’s the safest SSH port? A: Ports 49152-65535 (dynamic/private ports) are less commonly scanned but also less standard. Choose any port > 1024 that isn’t already used.
Q: Should I disable password authentication completely? A: Yes, if everyone uses SSH keys. In enterprise environments, disable password authentication for all users except those with strong MFA.
Q: How do I check who’s currently connected via SSH?
A: Use w, who, or last commands. For detailed session info, sudo ss -tunp | grep ssh shows active connections.
Discussion
Loading comments...