Firewall con WAF for WordPress

Last Revised: October 2, 2021

If we want to automatically block some attacks we can use fail2ban, a tool that is usually installed on Linux systems that block multiple requests.

Taking advantage of the fail2ban technology we can apply a series of rules and, in case of attack, the firewall will be responsible for adding the block for as long as it is established.

For this we will use WAF for WordPress, which includes several blocking functionalities; mainly we will use two of them: the first that analyzes the HTTP requests that arrive by the URL, and the second that analyzes requests to the core.

IMPORTANT: A firewall can filter valid traffic, so it is highly recommended to carefully analyze the exceptions or plugin configurations that we may have, since functionalities can be limited.

This tutorial has been created on a VPS. You can create your own VPS from 3€/month.

In addition, you have the possibility to create your VPS with the WordPress image in one click.



  • WordPress
  • Fail2Ban

Configuring Http_Analyzer


The first part of the Firewall is the one that reviews HTTP requests. In this case we will have to analyze all the requests just when they arrive and before anything from WordPress is loaded.

We will start by entering the folder where we have the wp-config.php, where we will download the Firewall file.

wget -O waf4wordpress-http-analyzer.php

You can also manually download the ZIP with all the files and we will find it inside the folder http-analyzer.


Now that we have the file, we must configure it. To do this we will add the following lines at the beginning of the file wp-config.php :

require_once __DIR__ . '/waf4wordpress-http-analyzer.php';
new Waf4WordPressHttp_Analyzer();

This will make the file look something like this:

require_once __DIR__ . '/waf4wordpress-http-analyzer.php';
new Waf4WordPressHttp_Analyzer();
The base configuration for WordPress
The wp-config.php creation script uses this file during the
installation. You don't have to use the web site, you can
copy this file to "wp-config.php" and fill in the values.
This file contains the following configurations:
* MySQL settings
* Secret keys
* Database table prefix
@package WordPress
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'labasededatos' );
/** MySQL database username */
define( 'DB_USER', 'elusuario' );

What you review

The system analyzes the following:

  • Custom CDN headers *
  • Request URI length (2500 bytes)
  • User Agent length (472 bytes)
  • HTTP methods
  • Two forward slashes in URI
  • Encoding URI
  • Blacklist URI
  • HTTP protocol
  • Request for non-existent PHP file
  • Request for robots.txt in a subdirectory
  • Request with author query field (author sniffing)
  • PHP and Shockwave Flash file upload
  • HTTP/POST without User Agent
  • Accept header
  • Content-Length header
  • Content-Type header
  • Accept-Language header
  • Referer header *
  • Request size for logins *
  • Login username blacklist (log POST variable) *
  • Accept-Encoding header
  • IE8 and modern browser (Mozilla/5.0) login
  • Cookie test (wordpress_test_cookie) *
  • Connection header *
  • Login from Tor exit nodes *

Advanced settings

In the configuration file we can add some configurations according to our needs.

For example, if we want to use the Close in requests instead of a Keep-Alive, we can use this:

define( 'W4WP_ALLOW_CONNECTION_CLOSE', true );

Or for example, if we want to block requests from Amazon CloudFront that are not static, we can use this:


The full list of options is this:

  • (boolean) W4WP_POST_LOGGING allows the registration of all POST requests, even normal ones
  • (integer) W4WP_COUNT activation limit for fail2ban, maxretry
  • (integer) W4WP_MAX_LOGIN_REQUEST_SIZE maximum size of the access request
  • (string) W4WP_CDN_HEADERS a list separated by two HTTP header points that are recognized by the CDN
  • (boolean) W4WP_ALLOW_REG allows logging in WordPress, disables the referer and tests cookie controls
  • (boolean) W4WP_ALLOW_IE8 allows access with Internet Explorer 8 as well (IE8 is not a Mozilla/5.0 browser)
  • (boolean) W4WP_ALLOW_OLD_PROXIES allows login requests in HTTP/1.0
  • (boolean) W4WP_ALLOW_CONNECTION_EMPTY allows requests without HTTP connection header
  • (boolean) W4WP_ALLOW_CONNECTION_CLOSE allow other HTTP connection headers in addition to keep-alive
  • (boolean) W4WP_ALLOW_TWO_CAPS allow usernames such as JohnDoe (with two capital letters)
  • (boolean) W4WP_DISALLOW_TOR_LOGIN to block logins from Tor exit nodes

To detect the IPs of users/clients:

  • HTTP_CF_CONNECTING_IP (Cloudflare)
  • HTTP_INCAP_CLIENT_IP (Incapsula)
  • HTTP_X_FORWARDED_FOR (Amazon CloudFront, can be a comma-separated list of IP addresses)


All connections with HTTP2 and SPDY are persistent connections, so we should activate:

define( 'W4WP_ALLOW_CONNECTION_EMPTY', true );

Configuring Core_Events


The second part of the Firewall is the one that reviews the events of the Core. This only reviews those functions that have to do with access to the panel and registered users.

This system works as a Must-Use plugin, so we must check that we have everything ready for it.

Once we are in the main folder of WordPres we will access the one of cntenidos, and once there we will validate that we have the folder mu-plugins.

cd wp-content/
ls -la

If the folder does not exist, we will create it.

mkdir mu-plugins

And we will access it.

cd mu-plugins

Now that we are there we will download the plugin. It will be activated automatically and cannot be disabled from the dashboard.

wget -O waf4wordpress-core-events.php

You can also manually download the ZIP with all the files and we will find it inside the folder core-events.

Why “Must Use”

  • Early execution: Must-Use plugins run earlier than regular plugins, causing less load on the server in the event of a DoS attack.
  • Security: Cannot be disabled, only manipulated by WordPress administrators.
  • Speed: because it is much simpler than the normal plugin with options.

What you review

  • Prevents anyone from accessing the site (disabled by default).
  • Avoid redirects to (log in only to /admin/ /wp-admin/ or /wp-login.php).
  • Stops brute force attacks (multiple login probes and password reminder attacks from an IP address).
  • It stops robots scanning non-existent URLs (404s, redirects, hacking simple URLs, misinterpreted relative protocols).
  • Responds with HTTP/403 Prohibits robots on non-frontal requests.
  • Stops showing 404 pages to robots but sends HTTP/404.
  • Prohibits 404 sequential requests (from the same IP address).
  • Prohibition of any XMLRPC-based authentication (even successful ones).
  • Prohibition of invalid requests from AJAX, XMLRPC and other requests handled by wp_die().
  • Prohibition of unknown actions of admin-ajax and admin-post.
  • Stops spammers in cooperation with the Contact Form 7 Robot Trap plugin.
  • Records WordPress logins and logouts.

Advanced settings

Prevent access to unmaintained sites

To deny access to the user copy this to .wp-config.php

define( 'W4WP_DISABLE_LOGIN', true );

Allow unlimited redirects for sites with non-canonical links

To allow unlimited canonical redirects, copy this to the wp-config.php.

define( 'W4WP_ALLOW_REDIRECT', true );

About this document

This document is regulated by the EUPL v1.2 license, published in WP SysAdmin and created by Javier Casares. Please, if you use this content in your website, your presentation or any material you distribute, remember to mention this site or its author, and having to put the material you create under EUPL license.