Below is an excerpt from my blog about how to configure rate limiting in Nginx specifically for wp-login.php.
Nginx has some great documentation on how to implement rate limiting, but I am going to provide an example of how to optimize it for WordPress. Setting up rate limiting in Nginx is simple, and only requires two components:
- We must define a zone in the main
nginx.conf
file.
- We must implement that zone in the WordPress login location block. To define the zone, we use
limit_req_zone
and, optionally, limit_req_status
. These directives go inside the http
block of the main nginx.conf
configuration file.
The code:
http {
limit_req_zone $binary_remote_addr zone=wordpress:10m rate=15r/m;
limit_req_status 429;
}
The above snippet defines a 10 MB zone named “wordpress” that allows a maximum of 15 requests per minute from any one IP address. The limit_req_zone
requires a variable, or key. In this case, the key is $binary_remote_addr
, or the IP address of the client. Nginx will use a maximum of 10 MB of memory to store the keys, and if a key exceeds the maximum number of allowed requests, Nginx will terminate the connection and return the status code defined in limit_req_status
. The default code is 503 Service Unavailable
, but I prefer the more specific 429 Too Many Requests
response. Keep in mind that Nginx will display a blank page to the client for non-standard HTTP codes if you have not set a custom error page using the error_page
directive.
You can name the zone anything you want (it is named “wordpress” in the example above) and you can also define any rate limit you feel is appropriate. I found that allowing a maximum of 15 requests per minute is restrictive enough to severely hamper a brute-force attack but is permissive enough not to interfere with end-users who legitimately mistyped their passwords.
To actually use the zone, we must implement it by adding this code to the WordPress login location block:
location = /wp-login.php {
limit_req zone=wordpress;
# add your PHP fastcgi config here
}
This tells Nginx to limit requests to the /wp-login.php
page using the parameters specified in the zone we defined above. Make sure you replace “wordpress” with whatever you named your zone in the previous step. Restart or reload Nginx and rapidly refresh your login page to test if the new brute-force protection is working. If you refresh faster than the rate you defined in limit_req_zone
, the server will return the status code defined in limit_req_status
.
Obligatory note: if you’ve read other guides on how to set up rate limiting with Nginx, you may have seen other syntaxes used, such as limit_req zone=one burst=1 nodelay
. The burst
and nodelay
options are more complex and allow you to control what happens to excess requests. They are not necessary in this context, since we want any excess brute-force attempts to be immediately rejected, but I would highly encourage you to read the documentation for them here.
Source: https://blog.arnonerba.com/2016/07/server-logs-explained-part-3