One annoyance of running a publically-accessible WordPress site is the bots that attempt to rapidly try thousands of login attempts via /wp-login.php.
Even if none of the guesses are ever likely to work, the site will waste resources running PHP and SQL to confirm that to be the case.
A barrier to these drive-by hack attempts can be added using nginx's http_limit_req, where rate limiting is applied only to POST requests for the login page, not affecting the rest of the site.
-
In
/etc/nginx/conf.d/login-limit.confwe create the zoneLOGINLIMIT.1mis the size of the shared memory zone for tracking requests, and15r/mlimits to 15 requests per minute (ie 1 every 4 seconds).map $request_method $posting_id { default ""; POST $binary_remote_addr; } limit_req_zone $posting_id zone=LOGINLIMIT:1m rate=15r/m;
-
Add a reusable configuration snippet to
/etc/nginx/snippets/wordpress-login-limit.phplocation ~ /wp-login.php$ { limit_req zone=LOGINLIMIT; limit_req_status 429; include /etc/nginx/fastcgi.conf; fastcgi_pass unix:///run/php/php-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root/wp-login.php; }
-
Call it from the host configuration in, eg,
/etc/nginx/sites-available/example.comserver { ... include /etc/nginx/snippets/wordpress-login-limit.conf; ... }
We use $binary_remote_addr as the key for lookups, but other keys could be used, such as an X-Forwarded-For: header.
Limits don't even have to be based on IP address - other variables, eg $geoip_country_code, could be used creatively if appropriate.
(Restricting checks to POST requests was adapted from a Reverb.com blog post).