To block recurring failed login attempts in WordPress, for example to prevent brute-force attacks, you can use Fail2ban. This tool is usually installed by default in most panels such as HestiaCP, and you will need to create the definition file to do this.
The default path is "/etc/fail2ban/filter.d/", so you can use a text editor over SSH to create the file as follows (the vi editor, for example):
# vi /etc/fail2ban/filter.d/wordpress.conf
You must include the following definition:
[Definition]
failregex = ^<HOST> .* "POST .*wp-login.php
^<HOST> .* "POST .*xmlrpc.php
Once created, you must specify in the file that fail2ban uses to configure jails the parameters for the new WordPress definition. Therefore, modify the file using a text editor:
# vi /etc/fail2ban/jail.conf
And add the following values at the end:
[wordpress]
enabled = true
filter = wordpress
port = http,https
action = iptables-multiport[name=wordpress, port="http,https", protocol=tcp]
logpath = /var/log/apache2/domains/*error.log
maxretry = 10
findtime = 600
bantime = 7200
As you can see, logpath specifies the path to the HestiaCP error logs for the domains with a * because it separates the domain logs. Therefore, you can modify the path to check a particular one or another log path.
In HestiaCP, another way to do this would be to create individual jails only for the domains you want.
Finally, reload the fail2ban configuration to apply the change using the following command:
# systemctl reload fail2ban.service
To verify that it is working correctly, run the following command, which shows the jails that are active:
# fail2ban-client status
Then you can test it by making failed attempts and checking the IPs banned by the WordPress jail:
# fail2ban-client status wordpress
To unban an IP banned by this jail, use the following command:
# fail2ban-client set wordpress unbanip DIRECCIONIP
The following steps are only necessary to use Cloudflare
To use Cloudflare as a CDN with Fail2Ban, you must use the API provided by Cloudflare, because if you do not configure it this way, it will continue allowing access to the IP that should have been blocked. It would also be possible to use the "Real IP" to block attempts, but in this case only the procedure for Cloudflare API v4 will be described.
You must add the following file in the fail2ban location within action.d; in HestiaCP it is already created by default:
# vi /etc/fail2ban/action.d/cloudflare.conf
In HestiaCP, you can modify it just to enter the cfuser and cftoken obtained from Cloudflare using the link https://dash.cloudflare.com/profile/api-tokens. The content would be as follows:
# Get Cloudflare API key: https://dash.cloudflare.com/profile/api-tokens use the Global API Key
# CloudFlare API error codes: https://www.cloudflare.com/docs/host-api.html#s4.2
[Definition]
# Option: actionstart
# Notes.: command executed on demand at the first ban (or at the start of Fail2Ban if actionstart_on_demand is set to false).
# Values: CMD
actionstart =
# Option: actionstop
# Notes.: command executed at the stop of jail (or at the end of Fail2Ban)
# Values: CMD
actionstop =
# Option: actioncheck
# Notes.: command executed once before each actionban command
# Values: CMD
actioncheck =
# Option: actionban
# Notes.: command executed when banning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: <ip> IP address
# <failures> number of failures
# <time> unix timestamp of the ban time
# Values: CMD
#
# API v1
#actionban = curl -s -o /dev/null https://www.cloudflare.com/api_json.html -d 'a=ban' -d 'tkn=<cftoken>' -d 'email=<cfuser>' -d 'key=<ip>'
# API v4
actionban = curl -s -o /dev/null -X POST -H 'X-Auth-Email: <cfuser>' -H 'X-Auth-Key: <cftoken>' \ -H 'Content-Type: application/json' -d '{ "mode": "block", "configuration": { "target": "ip", "value": "<ip>" } }' \ https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules
# Option: actionunban
# Notes.: command executed when unbanning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: <ip> IP address
# <failures> number of failures
# <time> unix timestamp of the ban time
# Values: CMD
#
# API v1
#actionunban = curl -s -o /dev/null https://www.cloudflare.com/api_json.html -d 'a=nul' -d 'tkn=<cftoken>' -d 'email=<cfuser>' -d 'key=<ip>'
# API v4
actionunban = curl -s -o /dev/null -X DELETE -H 'X-Auth-Email: <cfuser>' -H 'X-Auth-Key: <cftoken>' \ https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules/$(curl -s -X GET -H 'X-Auth-Email: <cfuser>' -H 'X-Auth-Key: <cftoken>' \ 'https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules?mode=block&configuration_target=ip&configuration_value=<ip>&page=1&per_page=1' | cut -d'"' -f6)
[Init]
# Name of the jail in your jail.local file by default = [jail name]
name = default
# Option: cfuser
# Notes.: Replace <cfuser> in actionban and actionunban with cfuser using the following value
# Values: Your CloudFlare user account
cfuser = user@mail.com
# Option: cftoken (Global API Key)
# Notes.: Replace <cftoken> in actionban and actionunban with cftoken using the following value
# Values: Your CloudFlare API key
cftoken = TU_API_KEY
Then specify the new action in the jail.local file:
# vi /etc/fail2ban/jail.local
You must also modify it to include it in the appropriate jail for the Web service used on the server. If you use the HestiaCP panel, add the action to the jail created for Wordpress:
[wordpress]
enabled = true
filter = wordpress
port = http,https
action = cloudflare
# iptables-multiport[name=wordpress, port="http,https", protocol=tcp]
logpath = /var/log/apache2/domains/*error.log
maxretry = 10
findtime = 600
bantime = 7200
Finally, restart the fail2ban service:
# systemctl restart fail2ban
We hope this tutorial has helped you. Have you tried it? Leave us your comments! 🙂
Remember, if you have questions about this or any other issue related to your servers at Clouding, feel free to write to soporte@clouding.io We are here for whatever you need!