Protecting wp-login.php for WordPress is essential for brute force protection from hackers. Most WordPress administrators will use a plugin like All-in-One Security (recommended) or Wordfence to block users who are making excessive login attempts. The problem with the plugin technique is that these brute force protection methods are still expensive for your web server. When a user tries to log in, PHP processing occurs and MySQL queries are made to verify if the user is valid or not. If you are getting lots of failed login attempts then you will see CPU usage spike and RAM be unnecessarily used up.
Using a basic http authentication method with nginx is far less resource intensive than using a plugin. With the HTTP authorization popup no PHP or MySQL is required so your server will be using considerably less resources to protect itself against malicious attackers and hackers. We will configure fail2ban to scan the nginx log files and ban attackers automatically.
For this tutorial you will need shell access (root SSH access) to your web server running Debian or Ubuntu.
You must already have nginx, PHP and WordPress running to complete this guide.
Configure nginx with Basic HTTP Auth for WordPress
Install Apache utilities to get the .htpasswd file generator and fail2ban
sudo apt-get update
sudo apt-get install apache2-utils fail2ban -y
Create the .htpasswd file for a user called wpbullet
sudo htpasswd -c /etc/nginx/.htpasswd wpbullet
You will be asked for a password twice. This password will be md5 hashed and stored in the /etc/nginx/.htpasswd file
New password:
Re-type new password:
Adding password for user wpbullet
Have a look and you can see the .htpasswd file just contains a hashed version of your password
cat /etc/nginx/.htpasswd
Now we need to enable .htpasswd for nginx in the wp-login.php custom location, open your nginx virtual host
nano /etc/nginx/sites-available/wordpress
Make sure you have an nginx error log specified in your server block. fail2ban needs to scan error logs to find login failures.
Add the wp-login.php section, adjust your fastcgi_pass if you are still using PHP 5.
server {
listen 80;
server_name wp-bullet.com;
access_log /var/log/nginx/wp-bullet.com.access.log;
error_log /var/log/nginx/wp-bullet.com.error.log;
location = /wp-login.php {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
include fastcgi_params;
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
Ctrl+X, Y and Enter to Save and Exit.
Test the nginx configuration syntax is valid.
nginx -t
Restart nginx if you got not errors.
service nginx restart
Now we generate some log data so the nginx log is populated with http authorization failures. This will let us test if fail2ban will detect the login failures.
Make sure to use the right username and wrong password. Also use an incorrect user and password as each failure generates different log data.
Have a peek in your nginx log file
cat /var/log/nginx/wpbullet.error.log
Here we go.
2016/03/12 11:31:20 [error] 21062#21062: *1 user "wp" was not found in "/etc/nginx/.htpasswd", client: 192.168.60.1, server: 192.168.60.138, request: "GET /wp-login.php HTTP/1.1", host: "192.168.60.138"
2016/03/12 11:31:30 [error] 21062#21062: *1 user "bullet": password mismatch, client: 192.168.60.1, server: 192.168.60.138, request: "GET /wp-login.php HTTP/1.1", host: "192.168.60.138"
Now it’s time to create the filter for nginx
Configure fail2ban to Ban WordPress Hackers
fail2ban uses filters to detect violations and jails to ban users who violate the filter.
Create fail2ban Filter for nginx HTTP Auth
Create then nginx filter, if you are on the latest fail2ban you may already have this file, in which case you can skip down to testing using the fail2ban-regex command.
sudo nano /etc/fail2ban/filter.d/nginx-http-auth.conf
Add this which is a regular expression match for the logs above adapted from here
[Definition]
failregex = ^ \[error\] \d+#\d+: \*\d+ user "\S+":? (password mismatch|was not found in ".*"), client: <HOST>, server: \S*, request: "\S+ \S+ HTTP/\d+\.\d+", host: "\S+"(, referrer: "\S+")?\s*$
ignoreregex =
Ctrl+X, Y + Enter to Save and Exit.
Now we can test the nginx HTTP auth filter by scanning the error log specified in the nginx virtual host.
fail2ban-regex /var/log/nginx/wpbullet.error.log /etc/fail2ban/filter.d/nginx-http-auth.conf
You will see this output showing it found the login failures we generated before.
Running tests
=============
Use failregex file : /etc/fail2ban/filter.d/nginx-http-auth.conf
Use log file : /var/log/nginx/wp-bullet.error.log
Results
=======
Failregex: 2 total
|- #) [# of hits] regular expression
| 1) [2] ^ \[error\] \d+#\d+: \*\d+ user "\S+":? (password mismatch|was not found in ".*"), client: , server: \S+, request: "GET /wp-login.php.*$
`-
Ignoreregex: 0 total
Date template hits:
|- [# of hits] date format
| [2] Year/Month/Day Hour:Minute:Second
`-
Lines: 2 lines, 0 ignored, 2 matched, 0 missed
Create fail2ban Jail for nginx HTTP Auth
Make sure the you have a fail2ban jail folder
sudo mkdir -p /etc/fail2ban/jail.d
Create the fail2ban nginx http auth jail configuration file
sudo nano /etc/fail2ban/jail.d/nginx-http-auth.conf
Paste thie configuration which uses the filter we created before, scans all nginx log files and bans users for 6000 minutes who fail 3 times in a 60 second period.
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/*.log
findtime = 60
bantime = 6000
maxretry = 3
Now that we know have made the jail, test the fail2ban syntax so make sure it’s all working
sudo fail2ban-client -d
If you didn’t see any errors (warnings are OK) then we can restart fail2ban
service fail2ban restart
Checking the nginx HTTP Auth fail2ban Status
The fail2ban client can be used to show the statistics of its jails
sudo fail2ban-client status nginx-http-auth
During a local test I managed to get the gateway IP banned.
Status for the jail: nginx-http-auth
|- filter
| |- File list: /var/log/nginx/wp-bullet.error.log /var/log/nginx/error.log
| |- Currently failed: 0
| `- Total failed: 3
`- action
|- Currently banned: 1
| `- IP list: 192.168.60.1
`- Total banned: 1
You can also list the iptables
sudo iptables -L -n
This shows the iptables chain for limiting nginx HTTP Auth requests
Chain f2b-nginx-http-auth (2 references)
target prot opt source destination
REJECT all -- 192.168.0.1 0.0.0.0/0 reject-with icmp-port-unreachable
RETURN all -- 0.0.0.0/0 0.0.0.0/0
RETURN all -- 0.0.0.0/0 0.0.0.0/0
You will see lots of bots scanning and putting default passwords in. They will quickly be banned. After I install this WordPress security solution I do not need any heavy PHP plugins like WordFence to lock users out. My web server can spend more time using its resources more wisely like serving content to you super fast.
Sources
Protect nginx with Fail2ban on Ubuntu
fail2ban nginx HTTP Auth filter
Viewing iptables from fail2ban
3 thoughts on “Protect WordPress wp-login with nginx HTTP Auth + fail2ban”
Comments are closed.