Protecting your Amazon Linux WordPress server using fail2ban and Cloudflare

Protecting your Amazon Linux WordPress server using fail2ban and Cloudflare

Servers on the internet are under constant attack, usually from automated scripts trying to make use of your resources. WordPress installations are doubly attacked, because they’re often out of date and are relatively easy to take over. This article describes how to use fail2ban and Cloudflare to protect your Amazon Linux / Centos server, particularly against WordPress attacks.

What is Fail2Ban?

fail2ban at its core is a tool that monitors logs and takes user defined actions. It also keeps track of past actions, so for example it can ban IPs for a fixed period of time. Typically these actions change the Linux iptables firewall, but it’s very customisable and configurable. It’s relatively easy to have fail2ban make a REST request to change the rules on an external firewall like Cloudflare.

What is Cloudflare?

Cloudflare is a content distribution network (CDN) and web application firewall (WAF). This allows it to both accelerate websites and protect them against internet based threats. One of the great things about Cloudflare is their free plan, which gives you a good CDN, manual limited DDOS protection, though not really any WAF features until you go to the paid plans.

Why Fail2Ban with Cloudflare

We have all our DNS pointed at Cloudflare, which means all traffic to our server goes through CF. We’re going to configure fail2ban to add IP addresses to the Cloudflare firewall. This means requests that we don’t want never even make it to our server.

One pre-requsite here is you need to have configured your AWS security groups or network ACLs to only accept traffic from Cloudflare IP addresses. You can read our tutorial how to configure Cloudflare with AWS. If attackers can reach your instance directly you won’t get any benefit from this tutorial.

Note that SSH and such works directly to your server via IP, rather than through CloudFlare, so it won’t be affected. If you’ve whitelisted your own IP and used your hosts file to short circuit DNS any http(s) requests it won’t be affected either.

Installing Fail2Ban on Amazon Linux

This should be really easy, but there’s a trick. Fail2Ban is in the Linux EPEL repository and also in the Amazon Linux repository. The version in the EPEL repository didn’t work for me and caused much frustration. To install fail2ban from the Amazon Linux repository if you have the EPEL repository installed use this command

yum --disablerepo epel install fail2ban

Your configuration files are in /etc/fail2ban


Integrating Fail2Ban with Cloudflare

This lets fail2ban add and remove entries from the Cloudflare firewall.

Install the WP Bullet Cloudflare action, which lets fail2ban update the Cloudflare firewall via their v4 API . Get the latest version from that page, but in case the site goes down I’ve included that file at the end of this tutorial.


Integrating WordPress with Fail2Ban

The easiest way to get WordPress integrated with fail2ban is using the wp-fail2ban plugin. This plugin writes login attempts to a log file that fail2ban can read. Go ahead an install that on all your WordPress instances, activate it, and follow its install instructions. The key install instruction is

Copy wordpress-hard.conf and wordpress-soft.conf to your fail2ban/filters.d directory

cp /var/www/wp/wp-content/plugins/wp-fail2ban/filters.d/*.conf /etc/fail2ban/filter.d/

There are two filters here, hard and soft. The hard filter is triggered when someone does something known to be malicious, such as logging in with a username that doesn’t exist. The soft filter is for situations such as when passwords are entered incorrectly a few times. There’s probably more to it, you can read the documentation or source of the plugin if you want to know more.


Configuring Fail2Ban

fail2ban has two types of configuration files. Files ending in .conf are defaults, and are read. You generally shouldn’t change them. Files ending in .local override the settings in .conf, so this is where you put your configuration.

If you like you can also use fail2ban to add the bans to the local iptables firewall, but I haven’t bothered.

Here are the contents of my configuration files



This tells fail2ban which log file to monitor.

logtarget = /var/log/fail2ban/fail2ban.log



This configures the blocking you want. Make sure you set your ignoreip to include any servers or workstations you don’t want blocked. You can adjust the ban times and such, either in the top default section or for the wordpress-hard or wordpress-soft filters.



# "ignoreip" can be an IP address, a CIDR mask or a DNS host. Fail2ban will not
# ban a host which matches an address in this list. Several addresses can be
# defined using space separator.
ignoreip =

# "bantime" is the number of seconds that a host is banned.
bantime = 43200

# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime = 1800

# "maxretry" is the number of failures before a host get banned.
maxretry = 3

enabled = true
filter = wordpress-hard
logpath = /var/log/messages
maxretry = 1
port = http,https
bantime = 86400
action = iptables-multiport[name=Wordpress, port="http,https"]
 sendmail-whois[name=Fail2Ban, [email protected], [email protected]]

enabled = true
filter = wordpress-soft
logpath = /var/log/messages
maxretry = 3
bantime = 14400
port = http,https
action = cloudflare
 sendmail-whois[name=Fail2Ban, [email protected], [email protected]]


Next set up Fail2Ban to start when the server starts

sudo chkconfig fail2ban on

Manual Test

If you would like to test the action, take the ban / unban curl from below and run them manually from the command prompt, removing the “-o /dev/null” portion. eg

curl -s -X POST -H ‘X-Auth-Email: INSERT_YOUR_CLOUDFLARE_EMAIL‘ -H ‘X-Auth-Key: INSERT_YOUR_CF_TOKEN‘ \ -H ‘Content-Type: application/json’ -d ‘{ “mode”: “block”, “configuration”: { “target”: “ip”, “value”: “<ip>” } }’ \

The result should either have the word “success” in it somewhere, or give you a useful error message.


If you’ve followed this tutorial you’ll now have WordPress telling fail2ban what’s happening, with fail2ban blocking anyone attacking your WordPress install using the Cloudflare firewall. This should improve your WordPress and server security, with a minor advantage that there should be less crud in your log files.

If you have any questions, comments, suggestions, or improvements please let us know in the comments below 🙂


WP Bullet CloudFlare fail2ban action

This great action was provided by WP Bullet. You should really go over there to get the latest version, and it has additional content on testing that it’s working, but in case it’s taken down here’s the file.


  • Make sure curl is installed (yum install curl)
  • Get your CloudFlare API key from here (you’ll have to log into your account for this link to work)
  • Make sure you replace the text from the file below “put-your-cloudflare-email-here” and “put-your-API-key-here” with your Cloudflare account email and the API key you found above

The text below gets put into this file (NB: the unban URL was updated October 2018)

IMPORTANT NOTE: If you’re using fail2ban 8.10.0 you need to manually replace <cfuser> and <cftoken> with the actual user and token. Each occurs three times in the file below.




# Author: Mike Andreasen from
# Adapted Source:
# Referenced from: by NORM YEE
# To get your Cloudflare API key:


# Option: actionstart
# Notes.: command executed once at the start of Fail2Ban.
# Values: CMD
actionstart =

# Option: actionstop
# Notes.: command executed once 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 address
# number of failures
# unix timestamp of the ban time
# Values: CMD

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>" } }' \

# Option: actionunban
# Notes.: command executed when unbanning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: IP address
# number of failures
# unix timestamp of the ban time
# Values: CMD

actionunban = curl -s -o /dev/null -X DELETE -H 'X-Auth-Email: <cfuser>' -H 'X-Auth-Key: <cftoken>' \
$(curl -s -X GET -H 'X-Auth-Email: <cfuser>' -H 'X-Auth-Key: <cftoken>' \
          '<ip>&page=1&per_page=1' | tr -d '\n' | cut -d'"' -f6)


# Option: cfuser
# Notes.: Replaces <cfuser> in actionban and actionunban with cfuser value below
# Values: Your CloudFlare user account

cfuser = put-your-cloudflare-email-here

# Option: cftoken
# Notes.: Replaces <cftoken> in actionban and actionunban with cftoken value below
# Values: Your CloudFlare API key 
cftoken = put-your-API-key-here




Facebook Comments