How to Detect SSH Brute-Force Attacks on Your Linux Server

If your Linux server is reachable on port 22, it's being attacked. This isn't paranoia — it's arithmetic. Internet-facing SSH servers receive thousands of login attempts daily from automated scanners probing default credentials, weak passwords, and common usernames. Most small-team servers have no idea this is happening because nobody's watching the logs.

This post covers how to detect SSH brute-force attacks, understand the attack patterns in your auth logs, and stop them permanently.

The auth.log: Where the Evidence Lives

On Debian and Ubuntu servers, every authentication event is written to /var/log/auth.log. On CentOS and RHEL, it's /var/log/secure. These files contain every SSH login attempt — successful and failed.

A single brute-force run looks like this in the logs:

Apr 30 04:12:33 server sshd[4821]: Invalid user admin from 198.51.100.42 port 47832
Apr 30 04:12:34 server sshd[4821]: Failed password for invalid user admin from 198.51.100.42 port 47832
Apr 30 04:12:35 server sshd[4822]: Invalid user deploy from 198.51.100.42 port 47933
Apr 30 04:12:36 server sshd[4822]: Failed password for invalid user deploy from 198.51.100.42 port 47933

High-volume attacks produce hundreds of these lines per minute.

Manual Detection

To quickly check if you're under attack:

# Count failed login attempts in the last hour
sudo grep "Failed password" /var/log/auth.log | grep "$(date '+%b %d %H')" | wc -l

# Find the top attacking IPs
sudo grep "Invalid user\|Failed password" /var/log/auth.log \
| awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -20

# See all unique attacking usernames being tried
sudo grep "Invalid user" /var/log/auth.log \
| awk '{print $8}' | sort | uniq -c | sort -rn | head -20

If the first command returns more than 50 failures in an hour, you're actively being targeted. If the IP list shows a single source making thousands of attempts, that's a targeted credential attack.

Severity Thresholds

Not every failed SSH login is an attack. A developer who mistyped their password three times isn't an attacker. But the pattern matters:

Failed attempts (recent 50 log lines) | Assessment
< 10 | Normal — occasional mistype
10–29 | Warning — automated scanner likely active
30+ | Critical — active brute-force or credential stuffing attack

Tink monitors auth.log on every scan and automatically raises an ssh_anomaly issue when it detects these thresholds — you don't have to remember to check.

Permanent Fix: fail2ban

fail2ban watches your logs in real time and automatically bans IPs after a configurable number of failures. It's the right long-term solution.

# Install fail2ban
sudo apt-get install -y fail2ban

# Enable and start it
sudo systemctl enable --now fail2ban

# Verify it's protecting SSH
sudo fail2ban-client status sshd

Default configuration bans IPs for 10 minutes after 5 failures. That's usually enough to stop most automated scanners.

For more aggressive protection, create /etc/fail2ban/jail.local:

[sshd]
enabled = true
bantime = 3600
findtime = 600
maxretry = 3

This bans for 1 hour after 3 failures in 10 minutes.

The Real Fix: Key-Only Authentication

Banning IPs is defensive but attackers rotate through botnets faster than bans apply. The permanent fix is eliminating password authentication entirely:

# Verify your key-based login works FIRST — do not skip this step
ssh -i ~/.ssh/your_key user@your-server

# Then disable password authentication
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config

# Validate the config change
sudo sshd -t

# Apply it
sudo systemctl reload sshd

With PasswordAuthentication no, brute-force attacks become mathematically impossible — there are no credentials to guess.

Monitoring Continuously

The problem with auth.log analysis is that you have to remember to do it. Attacks happen at 3 AM on holidays. By the time you notice unusual server behavior, the attack may have been running for days.

Tink checks auth.log on every scan automatically. When it detects 10+ failed attempts, it raises a warning and sends a Telegram alert. At 30+ failures, it escalates to critical. The fix plan includes the specific grep commands to verify, fail2ban installation steps, and the sshd_config change — all ready to execute from the dashboard.

SSH brute-force detection isn't exotic security tooling. It's reading a log file that already exists on your server. The only question is whether anyone's reading it.