Skip to content

Instantly share code, notes, and snippets.

@gwire
Created December 13, 2022 22:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gwire/afed5de030a8c324b2665133cc37e486 to your computer and use it in GitHub Desktop.
Save gwire/afed5de030a8c324b2665133cc37e486 to your computer and use it in GitHub Desktop.
Rate-limiting WordPress login attempts with nginx

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.

  1. In /etc/nginx/conf.d/login-limit.conf we create the zone LOGINLIMIT. 1m is the size of the shared memory zone for tracking requests, and 15r/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;
  2. 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;
    }
  3. 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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment