A rate limit zone in nginx costs one shared memory block

Rate limiting at the web server is cheaper than in the application and protects the endpoints the application never gets to serve.

limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

location = /wp-login.php {
    limit_req zone=login burst=3 nodelay;
    limit_req_status 429;
}

# 10m holds about 160,000 addresses. $binary_remote_addr
# rather than $remote_addr because it is 4 bytes, not 15.

burst without nodelay queues the excess requests and serves them slowly, which is usually worse than refusing — a queued request holds a worker connection. With nodelay the burst is served immediately and the budget is still consumed, which is what most people mean. Behind a proxy, $binary_remote_addr is the proxy, so the zone key has to be the forwarded address and the proxy has to be trusted for that to mean anything.