It’s very easy to make mistakes with the htaccess Order directive, so if it’s not working here’s some tips to fix it (for Apache web servers).
If we get the ‘Deny, Allow’ bit the wrong way round it won’t do what we expect – at best it will do nothing, at worst it denies everybody access to our site. So tread carefully, keep a backup and test after making changes 🙂
IMPORTANT: Also see below as the order directive has been deprecated and there is a newer way to do this.
‘Order’ in htaccess does not work like other kinds of regular expressions (regex).
Key Point 1: Apache always makes THREE passes of the access statements.
It does NOT find the first match and then stop – and that’s what makes things go haywire if we’re not careful.
Why Is It Not Working!?
Here’s a typical “block some IP’s because they keep spamming my WordPress comments” htaccess:-
Order Deny, Allow Deny from 173.44.37. Deny from 96.47.225.178 Allow from all
Looks OK right? It’s allowing everything, but blocking a specific IP address, and an IP range (everything starting with 173.44.37).
Problem is – this does NOT work!
Look closer at that Order statement – Deny first, then Allow.
Key Point 2: This is NOT the order the statements are written. It’s the order in which they will be PROCESSED.
This is what actually happens in this case:-
- Apache processes the Deny statements
- Then processes the Allow statements
- Finally processes anything that doesn’t match either of these
But remember – as I said above, Apache does ALL three of these passes. It does NOT just exit at the first one matched.
So in this example:-
For our regular nice visitor, Apache doesn’t match any denied IP addresses on Pass 1. And then hits the ‘Allow All’ statement on Pass 2. Because we have used ‘All’ here, it matches. There’s no match on Pass 3 because we already matched on Pass 2. So the request is allowed.
If it’s one of our spammers however, Apache does match the IP whilst processing the deny statements. Great, so far so good. But then it processes the Allow statement and is told to ‘Allow All’ – BAM, we just let our spammer back in again!
That’s not what we intended. But the only way we’d know it wasn’t working was if we noticed the spam was still coming from those ‘blocked’ IP addresses!
How To Fix It!
In this case, the fix is as simple as reversing the Order statement. If we simply switch to ‘Order Allow, Deny’ to process the Allow statements first – now things should behave as expected, i.e.
Our spammer arrives. Apache checks for Allow statements, finds an ‘Allow All’ so initially flags the request to be allowed. But then makes a 2nd pass to check the Deny statements. Now it finds a match for the spammer’s IP address, and changes the flag to deny the request instead. The request is blocked.
For our nice visitor, the Allow matches and the Deny doesn’t. The request is Allowed.
Bottom line. The order of ‘Order’ is critical. So be very careful when copying htaccess snippets from other sites, as they may not behave quite as you might expect.
P.S. Don’t forget the 3rd pass entirely. If you’re NOT using an ‘All’ statement somewhere (either in an Allow or Deny) this WILL come into play.
The 3rd case defaults to the SECOND directive – being Allow or Deny depending on what Order you have them.
So for ‘Order Allow, Deny’ where there is no match for either case, the request will default to being Denied. More examples of that another time…
UPDATE: The New Easier Way
Thankfully the whole order directive is going away. It’s deprecated and will be removed from Apache eventually.
This is the new way to block an IP (available since Apache v2.4):-
<RequireAll>
Require all granted
Require not ip 123.123.123.123
</RequireAll>
Or the other popular use for these directives is to only allow certain IP addresses (e.g. to particular folders, or during maintenance etc). To do that simply use:-
<RequireAll>
Require ip 123.123.123.123
</RequireAll>
So remember, the old ‘order deny, allow’ is going away – start using this method now to prevent sites breaking in the future when Apache is upgraded.
Finally, somebody talking some sense on this subject! Thanks very much!
I have it correct as per this article and it still does nothing. The spam goes right by into moderation on my blog. Any help with a reason why would be greatly appreciated.
I have 3 virtual hosts on my server. I have an .htaccess in the root and then one in the root of each vhost identical.
I put the ones in the vhost dirs after the main one didn’t work. Nothing works, They ignore it and go through. Thanks
RewriteEngine On
RewriteBase /
order allow,deny
deny from 222.77.203.216
deny from 63.141.253.234
deny from 222.77.203.216
deny from 192.151.152.172
deny from 27.159.218.169
deny from 63.141.253.234
deny from 222.77.203.216
deny from 27.159.218.169
deny from 222.77.206.215
deny from 27.159.218.114
deny from 27.159.217.27
deny from 125.77.95.173
deny from 110.85.127.239
deny from 27.150.203.156
deny from 110.89.36.171
deny from 121.205.196.179
deny from 125.82.186.184
deny from 46.161.41.34
deny from 125.82.186.184
Allow from all
Darn comment spam 😉
Your rules look OK. But there could be a conflict elsewhere in the file or in the higher level directory file.
To make testing easier what I sometimes do is block just my own IP address (it won’t block your FTP access etc, but obviously don’t do this if your only access to htaccess is via WordPress), then you can instantly see what is and isn’t working. Hope that helps you narrow down where the problem lies?
This is actually my own server. That’s all there is in the file and I have them one each in the docroot for each host and then one in the root of the server, identical to this one.
Thanks again.
Hmm – you do have mod_rewrite enabled in Apache?
i just remoted into my church’s server with RD after putting the IP address in the file. It had no effect.
Well, this guy’s TEST says it’s working.
Also if you look under APACHE2HANDLER it says mod_rewrite is loaded. I dunno. I appreciate your time. I am no expert here.