A common threat for any publicly reachable Linux server is the relentless scanning and brute‑force attempts against the default SSH port (22). Attackers use automated tools to try thousands of username/password combinations, often exhausting system resources and potentially gaining access through weak credentials. This guide outlines a practical, layered defence combining port changes, log auditing, and automated blocking with Fail2ban and iptables.
Changing the Default SSH Port
Although not a security measure by itself, moving SSH to a non‑standard port drastically reduces the volume of automated scans and low‑effort attacks. Edit the SSH daemon configuration file:
vim /etc/ssh/sshd_config
Locate #Port 22, remove the comment character and set a custom port, for example Port 5454. Save the file and restart the service:
CentOS / RHEL:
systemctl restart sshd
Debian / Ubuntu:
service ssh restart
Verify the change with ss -tulpn | grep sshd or netstat -ntlp. From this point forward, all SSH connections must target the new port.
Auditing SSH Logs for Attack Patterns
The authentication log (/var/log/auth.log on Debian‑based systems, /var/log/secure on Red Hat) contaisn detailed records of every login attempt. Analysing these logs helps identify repeat offenders before deploying automated countermeasures.
Extracting IPs of Failed Login Attempts
Failed password entries are often written as Failed password for ... from X.X.X.X. Use grep and awk to isolate the source addresses:
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort -u
To count how many failures each host generated, sort, count and sort numerically:
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr
Identifying Successful Logins
A similar query reveals successful authentications, useful for verifying legitimate access or spotting compromised accounts:
grep "Accepted password" /var/log/auth.log | awk '{print $(NF-3)}' | sort -u
For a frequency list:
grep "Accepted password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr
Alternative Extraction Using sed
For environments where log line format differs, a more robust approach uses grep with Perl‑compatible regex:
grep -oP 'rhost=\K[^ ]+' /var/log/auth.log | sort | uniq -c | sort -nr
This matches the rhost= field directly and works regardless of the exact message structure.
Automated Blocking with Fail2ban and Iptables
Fail2ban monitors log files for patterns that indicate abuse and temporarily bans the offending IP using firewall rules. It relies on filters (regular expressions) and actions (iptables, firewalld, etc.). The default installation already ships with a comprehensive SSH filter.
Installation
CentOS / RHEL:
yum install -y epel-release
yum install -y fail2ban
systemctl enable --now fail2ban
Debian / Ubuntu:
apt-get update
apt-get install -y fail2ban
systemctl enable --now fail2ban
Configuring a Dedicated Jail for SSH
Do not modify the main /etc/fail2ban/jail.conf directly; instead, create a /etc/fail2ban/jail.local file that overrides the defaults. Below is a practical setup that uses iptables‑multiport to block traffic on all SSH ports after a few failed attempts.
[DEFAULT]
bantime = 600
findtime = 300
maxretry = 5
banaction = iptables-multiport
action = %(action_mwl)s
[sshd]
enabled = true
filter = sshd
port = 5454,22
logpath = /var/log/auth.log
maxretry = 3
findtime = 300
bantime = 3600
ignoreip = 127.0.0.1/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
Key parameters:
bantime: duration of the ban in seconds.findtime: time window in seconds during whichmaxretryfailures trigger a ban.maxretry: number of failures before banning.ignoreip: a list of CIDR networks or IPs that should never be blocked.
After editing, reload the service:
systemctl restart fail2ban
Monitoring Fail2ban Activity
Check the current bans and jail status:
fail2ban-client status sshd
Output shows the filter currently applied, the number of banned IPs and a list of those addresses. The logs are stored in /var/log/fail2ban.log and can be tailed in real time:
tail -f /var/log/fail2ban.log
Common administrative commands:
fail2ban-client set sshd unbanip 203.0.113.42 # lift ban for one IP
fail2ban-client unban --all # remove all bans
fail2ban-client reload # apply configuration changes
Adding a Low‑Interaction Honeypot on Port 22
To deceive casual attackers and gather threat intelligence, a honeypot can be placed on the now‑unused port 22. Tools like HFish (https://hfish.net) emulate SSH services, logging all interaction attempts and credentials used. This helps detect attack patterns without risking a real service. Deploying a honeypot should be done on a dedicated host or isolated container to prevent lateral movement.
By combining a non‑default SSH port, regular log analysis, and automatic iptibles bans through Fail2ban, servers can withstand the vast majority of brute‑force campaigns and remain manageable for administrators.