As you’ve most likely noticed over the past few weeks/months, there are a lot of brute force attack attempts happening pretty regularly. Bots are trying over and over again to login to just about any WordPress site, using any credentials they can come up with. While there are many ways to combat this, one of the simplest is to restrict access to the wp-login.php file altogether, only allowing specific people to get to it.
How We Did It
At the University of Mary Washington, we’re serving our public pages through nginx, which acts as a proxy cache server to the apache server that’s running our WordPress installation. Since our WordPress installation is actually running on apache, we were able to make our changes through .htaccess. However, because we’re running a proxy server in front of apache, we couldn’t use standard IP addresses when checking to see where our users were coming from, as nginx tells apache that everyone is coming from a local IP.
Instead, we had to use the X-Forwarded-For header to see what IP address they used to reach nginx. To do so, we also needed to use an environment variable within .htaccess.
Our code looks similar to the code sample below. We placed this code at the top of our main .htaccess file.
Important Notes
- Do not leave the regular expressions as they are in that sample. They are just samples, and, if left the way they are, they might either allow everyone to access your login page (which means you’re not accomplishing anything), or they might block access to everyone. Make sure the regular expressions match your internal IP addresses/ranges. You can add as many separate regular expressions as you want; you’ll just need to make sure that you assign a unique variable name to each one.
- If you only use a single IP address regular expression, you can delete the second regular expression from the sample, and you can delete the `env=AllowAccessAlt` from the `Allow from` directive.
- If you encounter a 500 internal server error when you make these changes, it’s highly likely that your server is not configured to allow these types of restrictions within .htaccess. At that point, you have two options:
- You can modify your apache configuration to allow override of the “Limit” directive within your root HTML directory
- You can attempt to place these restrictions within your apache configuration files, rather than doing so within .htaccess. This method has the downside of requiring you to restart apache each time you want to apply changes to those IP ranges.
- This configuration is specifically for environments that are running WordPress through apache, while running a proxy server (such as nginx or varnish) in front of apache. If you are using apache all by itself, without a proxy server, you will need to use regular IP directives, rather than using the X-Forwarded-For header. That format will differ.
- This configuration relies on the ability to set and use environment variables within .htaccess
- The sample above shows how to allow access from multiple env variables (multiple different IP address ranges). It can easily be modified to add more IP ranges, or to allow access from only one IP range.
- Setting an environment variable is done so using regular expressions, so make sure you escape any literal characters (such as the dot between the IP address octets).
- If you choose to set a custom error document, you can modify the last line of the sample to do so. You can point that to any address on the Web. In the example, it will be looking for an HTML file relative to the location of the .htaccess file (so, since the sample sets it to `403.html`, it will look for the document http://www.example.com/403.html and pull it in, assuming that your .htaccess file is located at http://www.example.com/.htaccess). If you set a full URL as the custom error document, apache will actually redirect to that URL. If you set a relative path, apache will attempt to load the contents of that file, without changing the address of the page the user attempted to access.
How Are You Restricting Access?
Do you have a different server configuration? If so, I’d love for you to share how you’re restricting login access. Let us know in the comments below.
Quick Tip: Restricting Access to WordPress Logins,
So are you (more or less) locking down WP access to on-campus only? Have you gotten push-back that people can’t use it off-campus? Or are you using a VPN or similar for that?
We do allow users to login to the campus network using VPN. Then, they can login to WordPress. We just implemented this restriction last week, so we’ve yet to see major backlash; the few people that stumbled onto the issue so far have been very understanding. The biggest issue we’ll face is with the handful of users (mostly students) that aren’t allowed access to VPN.
With the consulting I’ve done for other schools, I can tell you that it’s fairly common to require people to be behind the firewall before letting them login to WordPress. Of the three major schools I’ve done a lot of work with, only one of them lets me login without having to go through their VPN connection first.
As a side note; one other warning I forgot to mention in the article is that you just want to restrict access to wp-login.php. If you restrict access to the whole wp-admin folder, you have a higher chance of AJAX requests failing (since they have to go through wp-admin in order to work).
In my environment at Dawson College, the wp-admin folder is locked down along with wp-login.php. We’ve found that we were still getting hit at the root of /wp-admin/.
We’re mitigating that on the nginx level by having a location rule for wp-login.php with ip allows. Then a separate location rule for wp-admin but with an allow on wp-admin/admin-ajax.php. Seems to be working in our setup.
Great information. Thanks, Jonathan.