Bots hammering wp-login.php and xmlrpc.php
Automated login attempts arrive around the clock and can make the site slow and unstable. How to spot them in the logs and shut them out.
- You need
- Hosting panel
- Updated
Every WordPress site gets automated login attempts. Bots try common usernames, email addresses harvested from contact pages, and leaked passwords against wp-login.php and xmlrpc.php. They can also get usernames from WordPress itself, through the author archives (/?author=1) and the REST API (/wp-json/wp/v2/users). They can send several attempts a second from many IP addresses at once. Each attempt loads WordPress and queries the database, so even when nobody gets in, the traffic can make the site slow or unstable.
With strong passwords the bots are unlikely to get in, but the load is a problem in itself. The access log shows whether it's happening to you. The earlier the attempts are stopped, the less work the server has to do.
Limit attempts with a plugin
A plugin such as Limit Login Attempts Reloaded or Wordfence locks out IP addresses after a set number of failed logins. Limit Login Attempts Reloaded protects both wp-login.php and XML-RPC.
- Install and activate one of them under Plugins. Use only one such plugin at a time.
- Keep the default settings to begin with.
- Go to Users and check that no administrator has the username
admin. Also ask everyone to use strong passwords. With Wordfence you can also turn on two-factor authentication. - If you use Wordfence, turn on the Brute Force Protection option that prevents usernames from being discovered through
/?author=Nand the REST API.
The plugin stops the guessing, but the server still has to run PHP for every request. If the traffic is heavy, the requests have to be stopped before they reach WordPress.
Block xmlrpc.php
XML-RPC is an older interface for publishing from apps and other services. Jetpack needs it to connect the site to WordPress.com. If you don't use Jetpack or another service that connects through XML-RPC, you can block access to the file completely.
How you block it depends on the web server the site runs on.
Add this to the top of .htaccess in the root folder, where wp-config.php is:
<Files "xmlrpc.php">
Require all denied
</Files>
Open https://yourdomain.com/xmlrpc.php in your browser to check. Before the change the page says XML-RPC server accepts POST requests only. Afterwards you get an error page saying access is denied. If the text is still there, the rule doesn't work on your server.
Many guides recommend the xmlrpc_enabled filter instead. The filter only turns off the XML-RPC methods that require a login, and WordPress still loads on every request.
Restrict access to wp-login.php
You can't block wp-login.php, because that is where you log in. If everyone who logs in has a fixed IP address, you can restrict access to those addresses. Replace the address in the example with your own. If the site is behind Cloudflare, the server has to be set up to see the visitor's real IP address, or the rule locks out everyone, including you.
Add this to .htaccess:
<Files "wp-login.php">
Require ip 192.0.2.10
</Files>
If you switch networks or get a new IP address, you can't get in until someone changes the rule. The rule also locks out everyone else who uses wp-login.php. Visitors can't open password-protected posts, and nobody can reset their password from another IP address. The approach therefore suits only sites where you and your colleagues are the only ones who log in, and no posts are password-protected.
Move the login page
If you don't have a fixed IP address, you can move the login page to an address the bots don't know instead, for example with the WPS Hide Login plugin. The bots then get an error page when they try wp-login.php, and you log in at the new address. Write the address down. If you forget it, you have to disable the plugin over FTP to get back in.
See the attempts in the access log
The access log shows every request to the site. You download it from your hosting panel.
- Download the log for the last 24 hours.
- Search for
POST /wp-login.phpandPOST /xmlrpc.php. If you have SSH, you can count the lines like this:
grep -c "POST /wp-login.php" access.log
grep -c "POST /xmlrpc.php" access.log
- Look at the times and IP addresses. Hundreds of these lines an hour that don't come from you or your colleagues are bots.
Compare the times with when the site has been slow. If they match, you have found the cause.
When you're stuck
If the attempts come from thousands of addresses, or the site is still slow with the plugin and the blocks in place, the traffic has to be stopped before it reaches the server. That takes a firewall at your host or a service such as Cloudflare in front of the site, which means you need access to the hosting panel or DNS. Ask your hosting provider to go through the access log with you.
With Cloudflare in front of the site, you can create a custom WAF rule that sends everyone who opens wp-login.php through a bot check (Managed Challenge):
http.request.uri.path eq "/wp-login.php"
Cloudflare then stops the bots before they reach the server, and you only have to pass the check before you log in.