Back to tutorials
Tutorial

SSH Brute-Force Troubleshooting Tutorial (2026): Detect Attacks, Stop Lockouts, and Secure SSH on a Hosting VPS

SSH brute-force troubleshooting tutorial (2026): find attacks, stop lockouts, tune SSH and firewall rules, and verify fixes.

By Anurag Singh
Updated on Jun 26, 2026
Category: Tutorial
Share article
SSH Brute-Force Troubleshooting Tutorial (2026): Detect Attacks, Stop Lockouts, and Secure SSH on a Hosting VPS

Most SSH “hacks” on a VPS aren’t clever. They’re noisy password-spray bots. They trigger lockouts, flood your logs, and can overload services by hammering the daemon. This SSH brute-force troubleshooting tutorial shows how to confirm what’s happening, contain it without locking yourself out, and finish with an SSH setup you can defend.

The steps below assume Ubuntu 24.04 LTS or Debian 12 (common hosting choices in 2026). The same workflow also applies to AlmaLinux/Rocky.

You’ll pull evidence from the systemd journal, apply a small set of firewall controls, and tighten sshd settings. The goal is to reduce attack surface without breaking admin access.

Before you touch anything: confirm you still have safe access

During an active attack, “one quick change” can block your own IP. Create a recovery path first:

  • Open a second SSH session and leave it connected while you work.
  • If your host offers it, verify you can reach console access (VNC/serial) for emergency recovery.
  • Record your current public IP (the one you actually admin from):
curl -4 https://ifconfig.me
curl -6 https://ifconfig.me

If you host client sites and need predictable recovery, a managed platform can help. managed VPS hosting from HostMyCode keeps guardrails and fallback access in place while you harden the basics.

SSH brute-force troubleshooting tutorial: prove it’s brute force (not a real login issue)

Start by collecting evidence. On systemd servers, the journal is the fastest way to get an accurate picture.

1) Inspect recent SSH authentication failures

sudo journalctl -u ssh --since "1 hour ago" | tail -n 200

Scan for these recurring markers:

  • Failed password for
  • Invalid user
  • Repeating source IPs, or rapidly changing IPs within the same ASN/country

2) Count failures per source IP (fast triage)

sudo journalctl -u ssh --since "2 hours ago" \
  | grep -E "Failed password|Invalid user" \
  | sed -n 's/.*from \([0-9.]*\) port.*/\1/p' \
  | sort | uniq -c | sort -nr | head -n 20

Dozens or hundreds of hits from one IP is classic brute force. Low counts spread across many IPs usually means credential spraying.

3) Differentiate “I can’t login” from “SSH is blocked”

From your workstation, confirm basic TCP reachability first. Replace SERVER_IP:

nc -vz SERVER_IP 22
  • If you get succeeded, the network path is open. Focus on auth and sshd settings.
  • If it times out, check firewall rules and upstream provider blocks.

If you recently changed firewall rules, keep this guide nearby: firewall troubleshooting for locked-out SSH.

Quick containment: stop the noise without breaking SSH

You want containment that’s easy to undo. Use a safe pattern:

  • Allow your admin IP(s) first.
  • Then rate-limit (or otherwise restrict) everyone else.

Option A: UFW allowlist + safe defaults

If you use UFW, sequence matters. Allow your admin IP first. Then apply SSH rules.

# Allow your admin IP (replace with your real IP/CIDR)
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp

# Ensure SSH is allowed (if you rely on open access)
sudo ufw allow 22/tcp

# Enable UFW if not already enabled
sudo ufw enable
sudo ufw status numbered

If UFW is new territory, follow a full “don’t lock yourself out” setup here: UFW firewall configuration tutorial.

Option B: nftables rate-limit SSH (quiet, effective)

On Ubuntu 24.04, nftables is a clean way to slow attacks without maintaining a giant blocklist. This example rate-limits new SSH connections per source IP.

sudo nano /etc/nftables.conf

Add a minimal rule set. Adjust it if you already have nftables rules.

table inet filter {
  chain input {
    type filter hook input priority 0;

    ct state established,related accept
    iif lo accept

    # Allow ICMP (optional but helps troubleshooting)
    ip protocol icmp accept
    ip6 nexthdr icmpv6 accept

    # SSH rate limit: max 10 new connections/minute per IP
    tcp dport 22 ct state new limit rate 10/minute accept
    tcp dport 22 drop

    # Web
    tcp dport {80,443} accept

    # Drop everything else by default
    counter drop
  }
}
sudo nft -f /etc/nftables.conf
sudo systemctl enable --now nftables
sudo nft list ruleset

Rate limiting won’t fix weak credentials. It will cut log spam and make brute-force attempts less effective.

Fix the real exposure: harden SSH daemon settings safely

Containment buys you breathing room. Hardening removes easy wins like password auth, root SSH, and wide-open login targets.

On most hosting VPS setups, keys-only for admins is the right baseline.

1) Create or verify a sudo admin user (no direct root)

sudo adduser adminops
sudo usermod -aG sudo adminops

Then copy your SSH key:

sudo rsync --archive --chown=adminops:adminops ~/.ssh /home/adminops/

If you need a clean key-based setup from scratch, follow this step-by-step: SSH key setup tutorial.

2) Update sshd_config with measurable, reversible changes

On Ubuntu/Debian the file is usually:

  • /etc/ssh/sshd_config
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
sudo nano /etc/ssh/sshd_config

Apply these settings. Keep what you already have, and don’t duplicate keys.

# Safer defaults for a hosting VPS
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes

# Reduce attack “work”
MaxAuthTries 3
LoginGraceTime 20

# Keep it explicit
AllowUsers adminops

Important: Don’t turn off password auth until you’ve confirmed key-based login works in another session.

3) Validate config before restart (prevents self-inflicted outages)

sudo sshd -t

No output means the syntax is fine.

sudo systemctl restart ssh
sudo systemctl status ssh --no-pager

4) Optional: move SSH to a non-default port (reduce noise, not security)

This won’t replace keys or firewall policy. It mainly reduces drive-by scans aimed at port 22.

sudo nano /etc/ssh/sshd_config
Port 2222

Allow it in your firewall, then restart SSH:

sudo ufw allow 2222/tcp
sudo systemctl restart ssh

Test from your workstation:

ssh -p 2222 adminops@SERVER_IP

Add automated blocking with Fail2ban (without “mystery bans”)

Fail2ban still earns its place in 2026, as long as you configure it so bans are explainable and reversible. Aim for predictable behavior, not maximum aggression.

1) Install and enable Fail2ban

sudo apt update
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban

2) Create a local jail config for SSH

Leave the package defaults alone. Add a simple override under jail.d:

sudo nano /etc/fail2ban/jail.d/sshd.local

Start conservative. Adjust after you’ve watched traffic for a few days.

[sshd]
enabled = true
backend = systemd
port = 22,2222
maxretry = 5
findtime = 10m
bantime = 2h

# Avoid banning your own office/VPN range
ignoreip = 127.0.0.1/8 ::1 203.0.113.10/32
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

3) Investigate bans and unban cleanly

sudo fail2ban-client status sshd
sudo fail2ban-client get sshd banip
sudo fail2ban-client set sshd unbanip 198.51.100.55

If you support many client accounts (reseller or agency), predictable bans matter more than harsh bans. Keep settings mild at first. Tighten them once you know what “normal” looks like.

Stop log growth and make attacks easier to review

Brute-force traffic often creates a second problem: log growth. It can eat disk and hide real incidents.

Focus on two things: log hygiene and (if it fits your setup) centralization.

1) Check whether SSH logs are consuming real disk

sudo journalctl --disk-usage
sudo du -sh /var/log/* 2>/dev/null | sort -h | tail -n 15

If you’re already tight on space, clear bloat first so the server stays stable: disk space troubleshooting tutorial.

2) Keep your security evidence off the box (optional but smart)

Central logs help if an attacker gets far enough to try erasing traces. If you run multiple VPS nodes, shipping SSH logs to a single collector also makes reviews faster.

Use this guide for rsyslog + TLS: centralize SSH logs with rsyslog + TLS.

Verify the fix: prove brute-force attempts dropped and access still works

After each change, verify three things:

  • You can still get in.
  • Attack volume dropped.
  • Nothing else broke.

1) Confirm you can still log in with your intended method

ssh -i ~/.ssh/id_ed25519 adminops@SERVER_IP

If you moved ports:

ssh -p 2222 -i ~/.ssh/id_ed25519 adminops@SERVER_IP

2) Compare failure counts before vs after

Run the same “count failures per IP” command again after 30–60 minutes. You want fewer failures. You should also see Fail2ban reporting bans.

sudo fail2ban-client status sshd

3) Check for collateral damage (websites, mail, monitoring)

  • Make sure ports 80/443 are still open and sites load.
  • If the server also handles email, confirm SMTP/IMAP weren’t blocked by blanket firewall changes.
  • Confirm your monitoring agent (if any) still reaches the box.

Practical checklist for resellers and multi-admin teams

  • Keys-only for admin users; remove password auth.
  • No root SSH; use sudo with named accounts.
  • Allowlist admin networks if your team uses a fixed office IP or VPN.
  • Rate-limit SSH at the firewall (nftables/ufw) to reduce spikes.
  • Fail2ban with a clear ignore list; document how to unban.
  • Keep logs under control and consider shipping security logs off-host.

Common pitfalls (and how to avoid them)

  • Disabling password auth before confirming key login: keep a second SSH session open, and run sshd -t before restart.
  • Blocking your own IP with Fail2ban: set ignoreip for your office/VPN CIDR, and avoid aggressive maxretry at first.
  • Assuming a new SSH port is “secure”: it’s only noise reduction. Keys and firewall policy are what matter.
  • Leaving SSH exposed for all users: use AllowUsers or AllowGroups so only admin accounts can authenticate.

Where HostMyCode fits (and when to upgrade)

If brute-force noise has become a weekly chore, you’ve likely outgrown “set it and forget it” hosting. A VPS with consistent firewalling and reliable recovery access saves time.

It also reduces risk when client sites depend on your uptime.

For hands-on control, start with a HostMyCode VPS. If you’d rather hand off routine security and maintenance, consider managed VPS hosting. You can stay focused on websites, email, and migrations instead of late-night lockouts.

If you’re dealing with repeated SSH lockouts or constant login noise, HostMyCode gives you a stable place to fix it and keep it fixed. Choose a HostMyCode VPS for full control, or go with managed VPS hosting if you want help hardening, monitoring, and making changes safely.

FAQ

Should I change SSH from port 22 to something else?

It reduces random scan noise, but it doesn’t replace keys-only auth and firewall rules. Treat it as optional cleanup, not a security control.

How do I know if an IP is actually malicious?

If you see repeated Invalid user and Failed password attempts across many usernames, it’s almost always automated brute force. Legit admins usually fail a couple of times, then stop.

Fail2ban banned my office IP. What’s the fastest fix?

Unban it with fail2ban-client set sshd unbanip X.X.X.X, then add your office/VPN CIDR to ignoreip and restart Fail2ban.

What’s the minimum safe SSH configuration for a hosting VPS?

Keys-only authentication, root login disabled, a named sudo user, and either allowlisted admin networks or rate limiting. Add Fail2ban if you’re seeing repeated attempts.