Brute force bots hammering wp-login.php with 1000s of password attempts? Block them at Apache level before they even reach WordPress.
The Plugin-Free Solution:
Add to .htaccess in WordPress root:
# Limit wp-login.php access to specific IPs
<Files wp-login.php>
Order Deny,Allow
Deny from all
Allow from YOUR_IP_ADDRESS
Allow from YOUR_OFFICE_IP
</Files>
Replace YOUR_IP_ADDRESS with your actual IP.
Why This Works:
Apache blocks requests BEFORE PHP loads. Brute force bots get 403 Forbidden instantly:
With Login Limiter Plugin: 1. Apache receives request 2. PHP starts 3. WordPress loads 4. Plugin checks IP 5. Plugin blocks = Server still did work for 1-3 With .htaccess: 1. Apache receives request 2. Apache blocks (if IP not allowed) = 90% less server load
Dynamic IP Problem? Use fail2ban Instead:
If your IP changes, .htaccess whitelist won’t work. Use fail2ban to auto-block after failed attempts:
# /etc/fail2ban/filter.d/wordpress-auth.conf [Definition] failregex = ^<HOST> .* "POST /wp-login.php ignoreregex = # /etc/fail2ban/jail.local [wordpress-auth] enabled = true filter = wordpress-auth logpath = /var/log/apache2/access.log maxretry = 3 findtime = 600 bantime = 3600
After 3 failed logins in 10 minutes → IP banned for 1 hour
Alternative: Rate Limit wp-login.php
Limit requests to 5 per minute per IP:
<IfModule mod_rewrite.c>
RewriteEngine On
# Rate limit wp-login.php
RewriteCond %{REQUEST_URI} ^/wp-login\.php$
RewriteCond %{HTTP:X-Forwarded-For} !^$
RewriteRule ^(.*)$ - [F,L]
# Allow only 5 requests per minute
RewriteCond %{REQUEST_URI} ^/wp-login\.php$
RewriteCond %{REMOTE_ADDR} ^(.*)$
RewriteRule ^(.*)$ - [E=REMOTE_ADDR:%1]
</IfModule>
# Use mod_evasive or mod_qos for true rate limiting
Whitelist Your Country Only:
If all your users are from one country, block all others:
<Files wp-login.php>
Order Deny,Allow
Deny from all
# Allow USA only (use GeoIP database)
SetEnvIf GEOIP_COUNTRY_CODE US AllowCountry
Allow from env=AllowCountry
</Files>
Requires mod_geoip. Most attacks come from outside your country!
Check Attack Logs:
# See failed login attempts
grep "wp-login.php" /var/log/apache2/access.log | grep "POST" | wc -l
# See unique IPs attacking
grep "wp-login.php" /var/log/apache2/access.log | awk '{print $1}' | sort | uniq -c | sort -rn
# Typical output:
# 2847 requests from 185.xxx.xxx.xxx
# 1923 requests from 91.xxx.xxx.xxx
# = Bot networks hammering login
Performance Comparison:
1000 bot login attempts per hour: With Plugin (Wordfence, Limit Login Attempts): - All 1000 requests hit PHP - WordPress loads 1000 times - Plugin checks IP 1000 times - Database queries: 3000-5000 - Server load: HIGH With .htaccess: - Apache blocks 1000 requests - 0 PHP executions - 0 WordPress loads - 0 database queries - Server load: MINIMAL
Bonus: Hide wp-login.php Entirely
Rename login page (requires plugin like “WPS Hide Login” or manual .htaccess):
# Redirect wp-login.php to custom URL RewriteRule ^wp-login\.php$ /my-secret-login [R=301,L] RewriteRule ^my-secret-login$ /wp-login.php [L]
Bots keep attacking /wp-login.php (404), your real login is /my-secret-login
