10 Proven SSH Hardening Techniques to Stop Bruteforce Attacks
This guide shares ten battle‑tested methods for hardening SSH, from changing the default port and disabling root login to using key authentication, fail2ban, IP whitelisting, two‑factor authentication, bastion hosts, and automated monitoring, helping you build a multilayered defense against brute‑force attacks.
Introduction
At 3 a.m. a server’s CPU spiked to 100 % and the /var/log/secure file grew to several gigabytes filled with failed SSH login attempts, revealing a brute‑force attack. Statistics show that over 80 % of server compromises start with SSH password‑guessing, with millions of automated scripts scanning port 22 daily. This article presents ten practical SSH hardening methods that have protected hundreds of servers from intrusion for three years.
SSH Brute‑Force Threat Analysis
Typical attacks exhaust a server with 3 000–8 000 login attempts per day, often from foreign IPs (≈70 %). Peak activity occurs between 02:00–04:00 a.m. Once a password is cracked, malware can be installed within 12 minutes. Attack trends include distributed botnets, smart dictionaries, low‑frequency “time‑gap” attacks, and 0‑day exploits.
10 SSH Hardening Methods
Method 1: Change the Default SSH Port
Changing the port reduces automated scans by >95 %.
# Edit /etc/ssh/sshd_config
Port 23456 # original: Port 22
semanage port -a -t ssh_port_t -p tcp 23456
firewall-cmd --permanent --add-port=23456/tcp
firewall-cmd --reload
systemctl restart sshd
# Test
ssh -p 23456 user@server_ipNotes: Verify the new port is free ( netstat -tulnp | grep 23456) and keep a backup session.
Method 2: Disable Direct Root Login
# /etc/ssh/sshd_config
PermitRootLogin no
systemctl restart sshdCreate regular admin accounts and use sudo su - for privilege escalation.
Method 3: Use SSH Key Authentication
# Generate key pair
ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_ed25519_server
# Copy public key to server
ssh-copy-id -i ~/.ssh/id_ed25519_server.pub -p 23456 user@server_ip
# Server side
vim /etc/ssh/sshd_config
PubkeyAuthentication yes
PasswordAuthentication no
systemctl restart sshdPrefer Ed25519 keys; rotate every 3–6 months.
Method 4: Install Fail2Ban
# Install
yum install -y epel-release fail2ban fail2ban-systemd
# Create jail
cat > /etc/fail2ban/jail.d/sshd.local <<EOF
[sshd]
enabled = true
port = 23456
filter = sshd
logpath = /var/log/secure
maxretry = 3
findtime = 600
bantime = 3600
ignoreip = 127.0.0.1/8 192.168.1.0/24
EOF
systemctl enable fail2ban
systemctl start fail2banConfigure aggressive rules with incremental ban times if needed.
Method 5: IP Whitelisting
# /etc/ssh/sshd_config
AllowUsers [email protected].* [email protected]/24
# Or using TCP wrappers
# /etc/hosts.allow
sshd: 192.168.1.0/24
sshd: 203.0.113.0/24
# /etc/hosts.deny
sshd: ALLMethod 6: Two‑Factor Authentication (2FA)
# Install Google Authenticator
yum install -y google-authenticator qrencode
# Configure for user
google-authenticator
# PAM configuration
auth required pam_google_authenticator.so
# SSH config
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
systemctl restart sshdMethod 7: Limit Concurrent Connections
# /etc/ssh/sshd_config
MaxStartups 3:50:10 # start:rate:full
MaxSessions 3
MaxAuthTries 3
LoginGraceTime 30Method 8: Session Timeout
# /etc/ssh/sshd_config
ClientAliveInterval 300
ClientAliveCountMax 2
# Shell timeout
echo "export TMOUT=900" >> /etc/profile.d/timeout.sh
chmod +x /etc/profile.d/timeout.shMethod 9: Log Monitoring & Alerts
# rsyslog configuration
:programname, isequal, "sshd" /var/log/ssh.log
& stop
*.* @@logserver.company.com:514 # Simple alert script (ssh_monitor.sh)
#!/bin/bash
LOG_FILE="/var/log/secure"
ALERT_EMAIL="[email protected]"
WEBHOOK_URL="https://hooks.slack.com/services/xxx"
# ... (parses failures, sends email/slack, auto‑bans IP)Method 10: Use a Bastion (Jump) Host
# Deploy JumpServer via Docker
curl -sSL https://github.com/jumpserver/jumpserver/releases/download/v2.28.0/quick_start.sh | bash
cd /opt/jumpserver
./jmsctl.sh start
# Access via http://ip:80 (default admin/admin)Building a Multi‑Layer Defense
Combine network firewalls, application firewalls (Fail2Ban), strong authentication, least‑privilege authorization, and continuous audit. Example layered diagram:
Internet → [Network Firewall] → [App Firewall] → [Auth Layer] → [Authorization] → [Audit]Performance and Optimization
Hardening measures add varying overhead. Changing the port adds negligible latency; key authentication adds 5‑10 ms and ~2 MB memory; 2FA adds 2‑3 s latency and ~5 MB memory; Fail2Ban consumes ~50 MB; a bastion adds 100‑200 ms latency and ~200 MB memory. Optimize SSH client config for connection reuse and disable DNS lookups on the server.
# ~/.ssh/config
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
ServerAliveInterval 60
Compression yes
# Server side
UseDNS no
GSSAPIAuthentication no
Compression delayedAutomation Practices
Use Ansible to apply hardening across fleets.
# ssh_hardening.yml
---
- name: SSH Security Hardening
hosts: all
become: yes
vars:
ssh_port: 23456
allowed_users:
- sysadmin
- developer
tasks:
- name: Backup ssh config
copy:
src: /etc/ssh/sshd_config
dest: /etc/ssh/sshd_config.bak
remote_src: yes
- name: Configure SSH
lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: '^#?Port', line: 'Port {{ ssh_port }}' }
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
- { regexp: '^#?PubkeyAuthentication', line: 'PubkeyAuthentication yes' }
- name: Install Fail2Ban
package:
name: fail2ban
state: present
- name: Configure Fail2Ban
template:
src: jail.local.j2
dest: /etc/fail2ban/jail.local
notify: restart fail2ban
- name: Deploy SSH keys
authorized_key:
user: "{{ item }}"
key: "{{ lookup('file', 'keys/{{ item }}.pub') }}"
loop: "{{ allowed_users }}"
handlers:
- name: restart sshd
systemd:
name: sshd
state: restarted
- name: restart fail2ban
systemd:
name: fail2ban
state: restartedTroubleshooting & Disaster Recovery
Common issues:
Cannot connect after config change: Use console access, validate syntax with sshd -t, check logs via journalctl -u sshd -n 50, restore backup config.
Forgot custom port: Find listening port with netstat -tlnp | grep sshd or ss -tlnp | grep sshd, inspect /etc/ssh/sshd_config.
Key authentication fails: Ensure correct permissions ( chmod 700 ~/.ssh, chmod 600 ~/.ssh/authorized_keys), enable verbose client logs ( ssh -vvv), review server logs.
Disaster recovery steps include booting into single‑user mode, restoring a default sshd_config, cleaning suspicious files, and rebooting.
Compliance Checklist
Disable SSH protocol 1.
Enforce strong ciphers (AES‑256, SHA‑256).
Use keys ≥2048 bits (RSA) or ≥256 bits (ECDSA).
Lock accounts after 5 failed attempts (30 min).
Enforce password complexity (≥12 characters, mixed case, numbers, symbols).
Session timeout ≤15 min.
Retain audit logs ≥6 months.
Quarterly security assessments.
Conclusion
Implementing these ten SSH hardening techniques can reduce the risk of compromise by over 99 %, but security is an ongoing process. Continuously monitor, audit, and update your defenses to stay ahead of attackers.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
