← Back to Dashboard

How to Protect Your Server from Brute Force Attacks

A practical, service-by-service guide to stopping credential attacks before they succeed

The Problem: Every Server Is Under Attack

If your server has a public IP address, it is being attacked right now. This is not hyperbole. Within hours of deploying a new server with SSH on port 22, automated scanners will find it and begin trying username/password combinations. The same applies to any publicly accessible login form — WordPress admin panels, FTP servers, database interfaces, and API endpoints.

The attackers are not humans typing passwords. They are botnets running automated tools across the entire IPv4 address space. Tools like Masscan can scan all 4.3 billion IPv4 addresses in under five minutes. Once a target with an open service is identified, specialized brute-force tools like Hydra, Medusa, or custom scripts begin systematic credential testing. The wordlists they use combine common defaults (root/admin, admin/password) with billions of credentials leaked from data breaches.

The consequence of a successful brute force attack depends on what service was compromised. An SSH breach gives the attacker full shell access, which typically leads to cryptocurrency mining, botnet recruitment, data theft, or ransomware deployment. A WordPress breach leads to SEO spam injection, malware distribution via the site, or use as a phishing host. A database breach means direct access to sensitive data.

SSH Protection

SSH is the most targeted service on the internet. Protecting it properly is the single most impactful thing you can do for server security.

Disable password authentication entirely

The most effective measure. If password authentication is off, brute force becomes impossible regardless of attack volume.

# Generate SSH key pair (on your local machine)
ssh-keygen -t ed25519 -C "your-email@example.com"

# Copy public key to server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server

# Verify you can log in with the key
ssh -i ~/.ssh/id_ed25519 user@your-server

# THEN disable password authentication on the server
# Edit /etc/ssh/sshd_config:
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin prohibit-password
ChallengeResponseAuthentication no
UsePAM yes

# Reload SSH (keep your current session open!)
sudo systemctl reload sshd

Warning: Always test key-based login in a separate terminal before disconnecting. If your key doesn't work after disabling passwords, you'll lock yourself out.

Install fail2ban

fail2ban monitors authentication logs and temporarily bans IPs after repeated failures. It's the standard defense for servers that must keep password authentication available.

# Install
sudo apt install fail2ban    # Debian/Ubuntu
sudo yum install fail2ban    # RHEL/CentOS

# Create local configuration (survives package updates)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# Edit /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3        # Ban after 3 failed attempts
bantime = 3600      # Ban for 1 hour (increase for production)
findtime = 600      # Within 10-minute window
ignoreip = 127.0.0.1/8 YOUR_TRUSTED_IP

# Start and enable
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# Check status
sudo fail2ban-client status sshd

Change the default SSH port

Moving SSH to a non-standard port eliminates over 95% of automated scanning traffic. It's not security through obscurity when combined with real controls — it's noise reduction.

# Edit /etc/ssh/sshd_config:
Port 2222    # Choose any unused port above 1024

# Update firewall before reloading SSH!
sudo ufw allow 2222/tcp
# OR
sudo iptables -A INPUT -p tcp --dport 2222 -j ACCEPT

# Reload SSH (keep current session open!)
sudo systemctl reload sshd

# Connect with: ssh -p 2222 user@host

Restrict which users can log in

# In /etc/ssh/sshd_config:
AllowUsers deploy admin     # Only these users can SSH in
DenyUsers root test guest   # Explicitly deny common targets

# Or restrict by group:
AllowGroups sshusers
# Then add users: sudo usermod -aG sshusers deploy

HTTP / WordPress Protection

Web applications are the second most targeted surface. WordPress alone powers 40% of the web, making /wp-login.php and /xmlrpc.php universal brute force targets.

Rate limit login endpoints

# nginx rate limiting for WordPress
limit_req_zone $binary_remote_addr zone=login:10m rate=3r/m;

server {
    # Rate limit wp-login
    location = /wp-login.php {
        limit_req zone=login burst=3 nodelay;
        limit_req_status 429;
        include fastcgi_params;
        fastcgi_pass php-fpm;
    }

    # Block xmlrpc entirely (used for brute force and DDoS amplification)
    location = /xmlrpc.php {
        deny all;
        return 403;
    }

    # Restrict wp-admin to specific IPs (optional, very effective)
    location /wp-admin/ {
        allow 192.168.1.0/24;    # Your office IP
        allow 10.0.0.0/8;        # VPN range
        deny all;
    }
}

Enable two-factor authentication

Even if an attacker guesses the password, 2FA stops them. For WordPress, plugins like WP 2FA or Wordfence provide TOTP-based two-factor. For custom applications, use a library like PyOTP (Python) or speakeasy (Node.js). For critical infrastructure, FIDO2/WebAuthn hardware keys provide phishing-resistant authentication that cannot be brute forced.

fail2ban for HTTP brute force

# /etc/fail2ban/jail.local
[wordpress-login]
enabled = true
port = http,https
filter = wordpress-login
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 3600
findtime = 300

# /etc/fail2ban/filter.d/wordpress-login.conf
[Definition]
failregex = ^ .* "POST /wp-login.php
            ^ .* "POST /xmlrpc.php

FTP and Database Protection

FTP: Disable it entirely

FTP transmits credentials in plaintext and is inherently insecure. Use SFTP (which runs over SSH) instead. If you absolutely must use FTP, use FTPS (FTP over TLS) and restrict access to specific IP ranges.

# Disable FTP service
sudo systemctl stop vsftpd
sudo systemctl disable vsftpd

# If you must keep FTP, restrict to specific IPs:
# /etc/vsftpd.conf
tcp_wrappers=YES

# /etc/hosts.allow
vsftpd: 192.168.1.0/24

# /etc/hosts.deny
vsftpd: ALL

Databases: Never expose to the internet

MySQL (3306), PostgreSQL (5432), MongoDB (27017), and Redis (6379) should never listen on public interfaces. This is the most common cause of database breaches — not sophisticated attacks, but databases left open to the world with default credentials.

# PostgreSQL: bind to localhost only
# /etc/postgresql/14/main/postgresql.conf
listen_addresses = 'localhost'

# MySQL: bind to localhost only
# /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address = 127.0.0.1

# Redis: bind to localhost and require authentication
# /etc/redis/redis.conf
bind 127.0.0.1
requirepass YOUR_STRONG_PASSWORD
protected-mode yes

# Verify nothing is listening publicly:
sudo ss -tlnp | grep -E '3306|5432|27017|6379'
# Should show 127.0.0.1 only, NEVER 0.0.0.0

For remote database access, use SSH tunnels instead of exposing the port:

# Create SSH tunnel to remote database
ssh -L 5432:localhost:5432 user@database-server

# Then connect locally:
psql -h localhost -p 5432 -U dbuser mydb

Network-Level Defense

Firewall: Default deny, explicit allow

# UFW (Uncomplicated Firewall)
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp      # HTTP
sudo ufw allow 443/tcp     # HTTPS
sudo ufw allow 2222/tcp    # SSH (custom port)
sudo ufw enable

# nftables (modern replacement for iptables)
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input iif lo accept
nft add rule inet filter input tcp dport { 80, 443, 2222 } accept

VPN-only access for management

The strongest network-level protection: require a VPN connection for SSH and all management interfaces. WireGuard is lightweight and fast:

# Install WireGuard
sudo apt install wireguard

# Allow SSH only from WireGuard interface
sudo ufw allow in on wg0 to any port 22
sudo ufw deny 22/tcp    # Block SSH from public internet

Port knocking (alternative to VPN)

Port knocking hides SSH behind a sequence of connection attempts to specific ports. Only after the correct sequence does the SSH port open for the source IP. Less robust than a VPN but useful on systems where VPN is impractical.

Proactive Defense: Pre-Block Known Attackers

The most advanced defense is proactive: block known attackers before they ever reach your login forms. By integrating threat intelligence feeds, you can deny connections from IPs with a proven track record of brute force activity.

#!/bin/bash
# Proactive threat blocking via WAYSCloud API
# Run via cron every 15 minutes

BLOCKLIST="/etc/wayscloud-blocklist.txt"

# Fetch top attacking IPs (high confidence, critical/high risk)
curl -s "https://ip.wayscloud.services/api/threats/live?limit=200" \
  | jq -r '.threats[] | select(.threat_score > 70) | .ip_address' \
  > "$BLOCKLIST.tmp"

# Apply blocks
while IFS= read -r ip; do
    iptables -C INPUT -s "$ip" -j DROP 2>/dev/null \
      || iptables -A INPUT -s "$ip" -j DROP
done < "$BLOCKLIST.tmp"

mv "$BLOCKLIST.tmp" "$BLOCKLIST"
echo "$(date): Blocked $(wc -l < $BLOCKLIST) IPs from threat feed"

For detailed integration instructions including fail2ban reporting and nginx configurations, see the WAYSCloud integration guide.

For a deep dive into SSH brute force specifically, see our detailed guide: What is SSH Brute Force? →

Server Hardening Checklist

Use this checklist to verify your server is protected against common brute force vectors:

  • SSH: Key-only authentication, password login disabled
  • SSH: Root login disabled or key-only
  • SSH: Non-standard port (if practical)
  • fail2ban installed and active on all login-capable services
  • Firewall: Default deny incoming, only required ports open
  • FTP: Disabled (use SFTP instead)
  • Databases: Bound to localhost only, not publicly accessible
  • WordPress: xmlrpc.php blocked, login rate limited, 2FA enabled
  • Management interfaces: Behind VPN or IP restriction
  • Threat intelligence: Proactive blocking of known attackers via API
  • Logs: Reviewed regularly or monitored with automated alerting
  • Updates: Automatic security patches enabled (unattended-upgrades on Debian/Ubuntu)

Related Threat Intelligence

What is SSH Brute Force? → How to Block Malicious IPs → Check if an IP is Malicious → How to Detect Malicious Traffic → What is a DDoS Attack? → API Integration Guide →