Using .htaccess deny returning 302 and not 403 forbidden

by Simon Hayter   Last Updated November 05, 2017 07:04 AM

I'm in the process of adding yet another layer of security to some of my WordPress installs, since some of my customers sites use shared hosting, and generally they do not ban users for brute force attempts on the WordPress login pages. Generally I would use fail2ban but sadly these accounts are on shared hosting and not in the position to make use of it.

I know there are WordPress plug-ins out there to prevent brute force but would rather a simple .htaccess method that will pretty much block all attempts via the wp-login.php file.

So I came up with this simple code that will block users other than myself, or at least those not using my ISP.

<FilesMatch "wp-login.php">
    deny from all
    allow from

The code works great however I would expect to see a 403 forbidden yet Firebug reveals 302 temporarily moved, the header status return looks like this:

HTTP/1.1 302 Moved Temporarily    
Date: Thu, 31 Dec 2015 00:24:15 GMT    
Server: Apache    
X-Powered-By: PHP/5.3.29    
Expires: Wed, 11 Jan 1984 05:00:00 GMT    
Cache-Control: no-cache, must-revalidate, max-age=0    
Pragma: no-cache    
Link: <>; rel=""    
Vary: Accept-Encoding    
Content-Type: text/html; charset=UTF-8    
Transfer-Encoding: chunked

While this does seem to stop the brute attacks it causes unnecessary multiple access attempts on the server, for example here is what FireBug looks like:


Other than using a redirect rather than deny is there anything I can do about this??

  • How can I return 403 with deny (not redirect)
  • Is this normal? or should I contact the web host?

Answers 3

Try this if you have rewrite module installed:

RewriteEngine On
RewriteCond %{REQUEST_URI} ^(.*)wp-login.php$
RewriteCond %{REMOTE_ADDR} !^xxx\.xxx\.xxx\.xxx$
RewriteRule ^(.*)$ - [R=403,L]

replace the xxx's with each octet of your IP address. For example, if your IP address is 111.222.333.444, then replace

RewriteCond %{REMOTE_ADDR} !^xxx\.xxx\.xxx\.xxx$


RewriteCond %{REMOTE_ADDR} !^111\.222\.333\.444$

If that won't work, then use this:

RewriteEngine On
RewriteCond %{REMOTE_ADDR} !^xxx\.xxx\.xxx\.xxx$
RewriteRule ^(.*)wp-login.php$ - [R=403,L]

Nice thing with these scripts is that the rules also apply to any kind of URL that ends in wp-login.php which I highly doubt 99% of websites will want to make available to the general public.

I also suggest using IP addresses instead of hostnames because the hostname will have to eventually resolve to an ip address anyway, and because updating .htaccess takes no time for apache to recognize the changes, I would suggest that each time you're logged into your ISP, you note your IP address and use that one in the script I shown above so that only your computer has access to the wp-login.php script.

January 20, 2016 21:53 PM

Is this normal? or should I contact the web host?

No, this is not normal.

X-Powered-By: PHP/5.3.29
Link: <>; rel=""  

But the HTTP response header shown has passed through PHP (WordPress?), not just Apache - as you would expect with a raw deny from ... directive. That Link: header suggests WP is somehow responsible.

Either there is some kind of conflict? Or a custom (ie. PHP) 403 ErrorDocument could be defined and overriding the expected response? Or the request is being routed through WP / what URL is being requested?

October 07, 2016 21:39 PM

Just to add something to this for others who may be experiencing the same issue. I was receiving the same series of 5 sequential 302 errors whether I was using:

<Files wp-login.php>
order deny,allow
deny from all
allow from

or using the rewrite rule shown above in my .htaccess file.

The reason for this was because I had failed to create a '403.shtml' page I created the page using cpanel and now receive a single '403' error when an denied IP address attempts to access the file... Like an idiot I had assumed that apache would generate a default 403 page

November 05, 2017 06:13 AM

Related Questions

403 or 301 domain pointing to our domain?

Updated July 29, 2015 14:01 PM