Rate limiting xmlrpc requests on WordPress using Nginx

WordPress based sites are target for most automated bots. Those bots look for various vulnerability in WordPress core, the themes, and the plugins. Then, there are some kids (and their kid bots) that target specific resources in a WP site. “xmlrpc.php” is one such resource. It uses XML-RPC protocol that does many things in WordPress. For example, it helps with remote sites to notify their mentions, to publish (and edit) articles using an app (such as WordPress app for Android / iOS). It is also used by many plugins such as Jetpack.

Naturally, xmlrpc.php file may be called multiple times in a day or in an hour (on a busy site). It may be called multiple times for every minute on a high traffic site. I have seen xmlrpc.php being accessed more frequently even on a site with no traffic too. Those traffic are likely from scan / scam bots, looking for vulnerabilities.

Since, there is no way to cache requests to xmlrpc.php, PHP and MySQL usage tend to go high quickly as every request needs a bit of php and MySQL. As a result, CPU usage spikes up, resulting in a wastage of precise CPU minutes. If we use platforms like AWS EC2, GCP, or Microsoft Azure where every CPU hour is charged, the cost of running a site can increase substantially.

In order to reduce the CPU usage, one solution is to completely block access to xmlrpc.php file. However, since this file is used for genuine purposes too, it is not recommended to disable access to this file. Alternatively, we can rate limit the requests to this file. A genuine request would not call this file multiple times per second. A decent limit is 1 request per second.

Let’s see how to implement rate limiting for xmlrpc in Nginx…

limit_req_zone $binary_remote_addr zone=wp_xmlrpc_limit:10m rate=1r/s;

server {
    server_name example.com;

    location = /xmlrpc.php {
        limit_req zone=wp_xmlrpc_limit;

        fastcgi_split_path_info ^(.+\.php)(/.+)$;

        if (!-f $document_root$fastcgi_script_name) { return 404; }

        # Mitigate https://httpoxy.org/ vulnerabilities
        fastcgi_param HTTP_PROXY "";

        include                     fastcgi_params;
        fastcgi_index               index.php;
        fastcgi_param   SCRIPT_FILENAME    $document_root$fastcgi_script_name;
        fastcgi_pass                fpm;
    }

    # other location blocks such as location / {}
}

Basically, we define a separate location block to process xmlrpc.php file and then insert two lines of code to introduce rate limit. The first line (starting with limit_req_zone) should be defined outside of server block. The other one (starting with limit_req) should be defined inside the newly introduced location block.

In the above code, we limited the requests at 1 request per second. We can fine-tune it depending on our use-case. There are other areas to fine-tune too such as implementing a separate log for xmlrpc requests. That’s for another day!

Happy Hosting!

Brotli on Nginx

Brotli compression was introduced by Google, exactly 3 years ago. It is yet to come by default with the standard Nginx packages of OS vendors or the official Nginx repo. Google maintains its own repo for brotli support on Nginx web server. However, it’s been two years since we had the last commit. Fortunately, a Googler, named Eugene Kliuchnikov, continues to develop a fork of Google’s repo. There are even plan to merge both repos. Still, there isn’t an easy way to compile Nginx from source.

Continue reading “Brotli on Nginx”

Oops Moments in DevOps

A post on a new year is usually about resolutions! But, isn’t the best time to revisit the last year’s mistakes and resolve to never repeat it this year (and years to come)?! Since, my strong skills are with DevOps, I’d like to share some oops moments (you may call them blunders) that you’d never want to do it, if you are starting on DevOps or if you just want to understand where things go wrong in DevOps. In general, you go by the defaults, you’d be in trouble in the future. Whatever software you use, make sure you understand the default values and what each of them does! Here are the top three mistakes that I did… Continue reading “Oops Moments in DevOps”

WP Rocket – Nginx configuration

I prefer open-source software and have been a long-time advocate of OSS in general. Recently, I started liking WP Rocket plugin that offers some unique features. I already have a perfect Nginx configuration for WP Super Cache plugin (that I consider as the best full-cache plugin till date). Since, WP Rocket uses disk caching like WPSC, I wanted to quickly convert the existing configurations to fit WP Rocket. I did succeed in it and you can find it in my WordPress-Nginx repo. Here I explain how WP Rocket stores the cached content and how it could be integrated into Nginx.

Continue reading “WP Rocket – Nginx configuration”

W3 Total Cache configuration for Nginx-Apache server stack

During the past 24 hours, there were two people had the following situation and were looking for a solution. Their use-case is…

I’m currently using a Nginx frontend / Apache backend setup. The W3 Total Cache plugin detects Apache and will only show me the Apache rewrite rules.

Here’s another quote from the other person who was looking for a similar solution…

The nginx.conf file does not exist. W3 Total Cache plugin detects that Apache is running – thus gives me the rewrites for that webserver instead. I am using Nignx in front of Apache – not a Nginx/PHP-FPM solution

Interesting, but not uncommon. So, I dived in and modified my existing Nginx rules for WP Super Cache plugin and provided a unique solution. Continue reading “W3 Total Cache configuration for Nginx-Apache server stack”

Efficient 301 Redirects

Traditionally, web sites use either www or non-www version to display their content to the visitors. Sub-domains are also becoming popular in recent times. When www is chosen as the preferred domain when installing WordPress (or after installing WordPress), whenever a visitor types non-www version of the site, WordPress redirects the visitor to the correct URL, the www version the site, through an internal 301 redirect. Google recommends this 301 redirect and Google WebMaster Tools has an option to set the preferred domain too. Continue reading “Efficient 301 Redirects”

Fix Incorrect IP Address in WP Comments

Image of an IP logoThe cost of running a VPS is becoming cheaper and cheaper. There are more things we could get for the same bucks. Once your site is ready for a VPS, there are multiple server stack options available, than the traditional LAMP setup. For example, you could completely ignore Apache and can use Nginx with php-fpm . Either case, you wouldn’t have any issues related to IPs in comments. However, on a complicated setups, such as Varnish => Nginx => php-fpm or Nginx => Apache, or Varnish => Apache, WordPress doesn’t display the IP address of the visitors correctly. There is nothing wrong with WordPress. It’s all about the implementation. Forwarding the correct client IP can be tricky as the complexity of the server stack increases. There are situations where you just don’t have any options to forward the correct address. Continue reading “Fix Incorrect IP Address in WP Comments”

W3 Total Cache 1.0? – Sneak Peek!

Banner of W3 Total Cache pluginUpdate (Feb 5, 2013): The beta version that I tested, has been released as version 0.9.2.6 with more features than mentioned below. So, this post is void as of February 5, 2013 (in less than 2 weeks of publishing it). :(-

W3 Total Cache is back in active development, nearly after a year. I’m one of the lucky people who got the opportunity to test the beta version of the upcoming release, probably 1.0.0.0! It brings a few new features, including a more-intuitive troubleshooter. Continue reading “W3 Total Cache 1.0? – Sneak Peek!”