WordPress Website Hardening for Nginx and OpenLiteSpeed (OLS)

8 min read

Table of Contents

The following WordPress hardening options will allow you to configure individual websites on an as-needed basis to easily increase their security.

This includes blocking xmlrpc.php, load-scripts.php, PHP executing in wp-content, block comments, block links OPML, block trackbacks, and block the wp-admin upgrade and install file.

These commands block these at the webserver (Nginx/OpenLiteSpeed) level, which means requests are blocked by the server before they have chance to hit your website.

The Additional Measures Tab

All of the following GP-CLI below can now be toggled ON and OFF directly inside your website’s configuration modal. These toggles will run the activation GP-CLI when toggled ON, and they will run the deactivation GP-CLI when toggled OFF.

By default, all settings are toggled off, unlike Fail2Ban and the Web Application Firewalls (WAFs). The reason for this is that these are their own individual measures, and they aren’t individual rulesets of a singular specific security feature.

Activation

To activate these settings, head to the Sites page inside your GridPane account and then click on the website that you wish to configure:

This will open up the website customizer modal. Next click through to the Security tab, and then the Additional Measures tab:

As pictured above, here you will find a toggle for each of the individual settings detailed in this article.

We highly recommend you read up on what each one does below and incorporate them into your security routines as appropriate. You do not need to run the GP-CLI commands if you are using the toggles inside your GridPane account.

SSH into your server

To run them, you will need to SSH into your server. See the following guides to get started:

Configure your WordPress sites with GP CLI Commands

Enable/Disable XML RPC

WordPress has a file named xmlrpc.php. It’s really a legacy feature that allowed you to login and interact with your site by remote, enabling data to be transmitted, with HTTP acting as the transport mechanism and XML as the encoding mechanism. It was the WordPress API before the REST API, except far less useful or secure.

And in recent years it has become a real pest – being the primary target for malicious Bots to overload your server.

By default, XML-RPC is active on your WordPress sites. If you aren’t using it, you should disable it, but if you do this at the WordPress level only, then your server can still be overloaded with requests that go nowhere. Instead, let’s drop it at the server level.

This CLI command creates the following include on Nginx:

/var/www/{site.url}/nginx/disable-xmlrpc-main-context.conf

Or here on OLS:

/var/www/{site.url}/ols/disable-xmlrpc-main-context.conf

Which contains configurations to:
– Deny Access to the xmlrpc.php
– Removes the X-Pingback header that WordPress adds

Disable XML-RPC with:

gp site {site.url} -disable-xmlrpc

Enable it again with:

gp site {site.url} -enable-xmlrpc

Enable/Disable Concatenating Load Scripts

WordPress has a feature that concatenates WP-Admin JS and CSS. While this may seem innocuous there are circumstances where this could be used to DoS a server, and in the age of HTTP/2 multiplexing, it isn’t really necessary.

More details can be found regarding CVE-2018-6389 here.
And a nice article by Bjørn Johanse regarding it here.

This CLI command creates the following include on Nginx:

/var/www/{site.url}/nginx/disable-load-scripts-concatenation-main-context.conf

Or here on OLS:

/var/www/{site.url}/ols/disable-load-scripts-concatenation-main-context.conf

Which contains configurations to:
– Deny access to ../wp-admin/load-scripts.php
– Deny access to ../wp-admin/load-styles.php

It also definest the following constant in your wp-config.php:

define('CONCATENATE_SCRIPTS', false);

Enable with:

gp site {site.url} -disable-concatenate-load-scripts

Disable with:

gp site {site.url} -enable-concatenate-load-scripts

Block/Unblock direct PHP script execution from wp-content and subdirectories.

Best practice should dictate that all WordPress PHP scripts are called directly by WordPress from within the loop. Assuming best practice is followed you can block PHP execution from all wp-content subdirectories with these CLI commands.

We already block php execution from wp-content/uploads/* so the recent zero day Elementor vulnerabilities would have been mitigated by default, but this command takes things one step further and will also disable direct PHP script execution from the web for any files within any plugin or mu-plugin.

Please be aware, some plugins actually want you to directly call from the web with cronjobs etc. Please ensure if you do so, to use the correct system user for the cronjob to ensure that sites remain isolated by PHP user.

If any plugin you use is allowing direct calling of a PHP script from within a plugin by third party web services – as opposed to using the recommended REST API methods to access WordPress, then the scripts will be being executed by the www-data server user, and will likewise not be isolated.

This CLI command creates the following include on Nginx:

/var/www/{site.url}/nginx/disable-wp-content-php-main-context.conf

Or here on OLS:

/var/www/{site.url}/ols/disable-wp-content-php-main-context.conf

Which contains configurations to:
– Deny access to ../wp-content/*.php

Block with:

gp site {site.url} -block-wp-content.php

Unblock with:

gp site {site.url} -unblock-wp-content.php

Block/Unblock WordPress OPML Links functionality

WordPress allows links to be imported or exported using the OPML format via the wp-links-opml.php file. Hitting this page presents an XML output and details of your WordPress installation. Somebad bots will try this page when exploring your site for information. If you are not using this feature, then we may as well disable it at the server level.

This CLI command creates the following include on Nginx:

/var/www/{site.url}/nginx/disable-wp-links-opml-main-context.conf

Or here on OLS:

/var/www/{site.url}/ols/disable-wp-links-opml-main-context.conf

Which contains configurations to:
– Deny Access to the wp-links-opml.php

Block with:

gp site {site.url} -block-wp-links-opml.php

Unblock with:

gp site {site.url} -unblock-wp-links-opml.php

Block/Unblock wp-trackbacks.php

WordPress has a built in mechanism to allow trackbacks, notifications on your posts that someone has linked to them. Unfortunately trackbacks have, in the past, led to several MySQL injection vulnerabilities and if unguarded can lead to a lot of Spam. If you are not using this feature, then we may as well disable it at the server level.

This CLI command creates the following include on Nginx:

/var/www/{site.url}/nginx/disable-wp-trackbacks-main-context.conf

Or here on OLS:

/var/www/{site.url}/ols/disable-wp-trackbacks-main-context.conf

Which contains configurations to:
– Deny Access to the wp-trackback.php

Block with:

gp site {site.url} -block-wp-trackbacks.php

Unblock with:

gp site {site.url} -unblock-wp-trackbacks.php

Block/Unblock upgrade.php

NOTE: With WordPress 5.6 this may result in your website’s dashboard returning a “page not found” error.

This WordPress core file is used to manage upgrades of core. You can disable access to this file at the server Level. Just remember to unblock whenever you need access to this file to upgrade. It is often used by Bots to identify a site as WordPress.

This CLI command creates the following include on Nginx:

/var/www/{site.url}/nginx/block-upgrade-main-context.conf

Or here on OLS:

/var/www/{site.url}/ols/disable-wp-trackbacks-main-context.conf

Which contains configurations to:
– Deny Access to the ../wp-admin/upgrade.php

Block with:

gp site {site.url} -block-upgrade.php

Unblock with:

gp site {site.url} -unblock-upgrade.php

Block/Unblock install.php

NOTE: With WordPress 5.6 this may result in your website’s dashboard returning a “page not found” error.

This WordPress core file is used to install WordPress, but since we do that for you then is there any need? It is also used by Bots to identify a site as WordPress. If you aren’t needing to install WordPress, then you can disable it at the server level. Sometimes during the management of your server, you might use this file for reinstalling WordPress, depending how you go about things, in such a case please remember to unblock the file.

This CLI command creates the following include on Nginx:

/var/www/{site.url}/nginx/block-install-main-context.conf

Or here on OLS:

/var/www/{site.url}/ols/block-install-main-context.conf

Which contains configurations to:
– Deny Access to the ../wp-admin/install.php

Block with:

gp site {site.url} -block-install.php

Unblock with:

gp site {site.url} -unblock-install.php

BETA CLI functions

The following functions are Beta and should not be used on any production server, but if you wish to help test them then they are provided for your use. They each have integrations beyond just Nginx/OpenLiteSpeed and include some MU Plugin functionality.

These really are beta, you have been warned.

Disable Emoji

Disable with:

gp site {site.url} -disable-emoji

Renable with:

gp site {site.url} -enable-emoji

Disable RSS

Disable with:

gp site {site.url} -disable-rss

Renable with:

gp site {site.url} -enable-rss

Disable Username Enumeration

This blocks all user enumeration attempts on your website. User enumeration is where bots probe your websites for valid usernames so they can attempt to brute force attack you.

For example, the URI “/wp-json/wp/v2/users/” on most WordPress websites openly shows admin names by default. It is well known, and bots will harvest your information from here and other places, then brute force your login page using the valid username/s.

NOTE: This will also block comments for users that are not logged into the website, so use with caution.

Disable with:

gp site {site.url} -disable-username-enum

Renable with:

gp site {site.url} -enable-username-enum

Block WP Scan Agent

Disable with:

gp site {site.url} -block-wpscan-agent

Renable with:

gp site {site.url} -unblock-wpscan-agent

Block WP Version

Disable with:

gp site {site.url} -disable-wp-version

Renable with:

gp site {site.url} -enable-wp-version