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.conf
we create the zoneLOGINLIMIT
.1m
is the size of the shared memory zone for tracking requests, and15r/m
limits 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.php
location ~ /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.com
server { ... 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).