I've been flooded with POST requests at /wp-login.php

September 2, 2014 18.5k views

Today and in the past few days I've been often flooded with POST requests that look like this: - - [02/Sep/2014:18:36:17 +0200] "POST /wp-login.php HTTP/1.0" 302 0 "-" "-" - - [02/Sep/2014:18:36:19 +0200] "POST /wp-login.php HTTP/1.0" 302 0 "-" "-" - - [02/Sep/2014:18:36:32 +0200] "POST /wp-login.php HTTP/1.0" 302 0 "-" "-" - - [02/Sep/2014:18:36:33 +0200] "POST /wp-login.php HTTP/1.0" 302 0 "-" "-" - - [02/Sep/2014:18:36:34 +0200] "POST /wp-login.php HTTP/1.0" 302 0 "-" "-"

These kind of requests uses significant resources on my server, and the PHP process is constantly using CPU cycles.

I've tried manually banning the IP address, but I had no luck. I've tried using the ngx_http_limit_req_module, but again no luck. I've found a tutorial on how to set-up a fail2ban filter to catch these kind of reqeusts from the access logs, but again no luck.

Today this IP flooded me with over 50.000 reqs and I needed to shut down the server for half an hour so it can stop.

Is there any proper automatic way to set up so the server can detect and block IP adresses that flood the server with requests like these? I don't want to use wordpress plugins or anything like that, since I have a couple of sites installed and I don't want to install security plugins to each of them.

Here's the fail2ban filter I have added:

failregex = ^<HOST> .* "POST /wp-login.php
ignoreregex =

And here's the rule implemented in jail.local

enabled = true
filter = wp-auth
action = iptables-multiport[name=NoAuthFailures, port="http,https"]
maxretry = 2

But I had no luck with this.

Any suggestions?

1 comment
6 Answers

Your fail2ban doesn't look right. Think you need a log file. I got this from

Hope it helps



enabled = true
filter = apache-wplogin
action = iptables-multiport [name = apache-wplogin, port = "http, https" protocol = tcp]
port = http, https
logpath = /var/log/httpd/access_log
maxretry = 5
findtime = 60
bantime = 86400



failregex = ^. * “POST. * / wp-login \. php HTTP. * 200e * $
ignoreregex =

Edit I can never get the code blocks to work right :(

  • fail2ban uses the default log pat /var/log/messages, that's why I didn't set up a path.
    I will try your config and see how it goes.


  • I've read the tutorial, it's nicely explained but I'm confused.
    I have HTTP 302 requests, while the tutorial mentions 200 requests

    "When you arrive on the wp-login.php space, you enter your login / password, if correct, wordpress lets you enter the administration area, and writes the code HTTP/302 “redirect” in your log file “accesslog”,you are redirected to the “wp-admin” folder. By cons, if you enter the wrong login / password, you stay on your wp-login page, and HTTP/200 code “OK” is registered in your accesslog file."

    I'm really confused

I know the OP was from a while ago, but hopefully this will help anyone finding this same issue.

Our solution uses fail2ban like the others, but with actions setup to use ufw commands since we love the simplicity of that firewall. Note that our log file is different from the default and includes the IP address the request was sent to first (othervhostsaccess.log), so remove the first "\S*" and space from regex for the normal access log. For some reason, this was the default when we set up the Wordpress droplet. YMMV.

# cat /etc/fail2ban/action.d/ufw.conf
actionstart =
actionstop =
actioncheck =
actionban = ufw insert 1 deny from <ip>
actionunban = ufw delete deny from <ip>

# cat /etc/fail2ban/filter.d/xmlrpc.conf 
failregex = ^\S* <HOST> .*POST .*xmlrpc\.php.*
ignoreregex =

# cat /etc/fail2ban/filter.d/wp-login.conf 
failregex = ^\S* <HOST> .*POST .*wp-login\.php.*
ignoreregex =

# cat /etc/fail2ban/jail.d/xmlrpc.conf 
enabled = true
filter = xmlrpc
action = ufw
logpath = /var/log/apache2/other_vhosts_access.log
bantime = 43200
maxretry = 2

# cat /etc/fail2ban/jail.d/wp-login.conf 
enabled = true
filter = xmlrpc
action = ufw
logpath = /var/log/apache2/other_vhosts_access.log
bantime = 600
maxretry = 6
findtime = 60

No changes were required to Wordpress or any plugins to install. This does mean that fail2ban can't actually tell if there was a failure, it just looks at how often those URLs were accessed.



You can deny the IP address using a firewall. If you're on Ubuntu I'd suggest using UFW as a frontend to IPTables.

First set up some basic rules that will open port 22 for SSH and port 80 for HTTP while denying any incoming requests for other ports:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp

Then, set a rule that will deny all requests from the IP address:

sudo ufw insert 1 deny from

Finally, enable the firewall:

sudo ufw enable
by Shaun Lewis
Learn how to setup a firewall with UFW on an Ubuntu / Debian cloud server.
  • I have UFW enabled, but there are 2 main drawbacks while using this to block the requests

    1. I need to manually add every IP address
    2. Requests are coming to port 80

    I need to set up unattended blocking. I don't want to look at logs all day searching for patterns and blocking IP addresses manually.

I still doesn't get it with the requests from the access log:

When I try to login with a incorrect username and password, i get a request like this - - [02/Sep/2014:23:55:47 +0200] "POST /wp-login.php HTTP/1.1" 200 1626 "" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0"

The requests that are coming from the IP address that is flooding me are - - [02/Sep/2014:21:30:07 +0200] "POST /wp-login.php HTTP/1.0" 302 0 "-" "-"

Why are mine HTTP 200, and why are those HTTP 302? Isnt 302 a redirect code? I don't get it

I've set up the following fail2ban filter:

failregex = <HOST>.*] "POST /wp-login.php 302
ignoreregex =

And added the following to the jail.conf


enabled = true
filter = wp-auth
port = http
action = iptables[name=wp-auth, port=http, protocol=tcp]
logpath = /var/log/nginx/access.log
maxretry = 3
bantime = 14400

This is the best solution for my problem..
Will wait and see if something happens

  • Would this give you better results?

    failregex = ^<HOST> - .*] "POST /wp-login.php HTTP/1.0" 302 0 "-" "-"

Have another answer? Share your knowledge.