homepage Welcome to WebmasterWorld Guest from
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Become a Pro Member
Home / Forums Index / Code, Content, and Presentation / Apache Web Server
Forum Library, Charter, Moderators: Ocean10000 & incrediBILL & phranque

Apache Web Server Forum

exclude root from maintenance redirect
Stop htaccess from redirecting root / or empty uri requests

 1:44 am on Jan 28, 2013 (gmt 0)

Hello all,

Wondered if you could help with this one.

The following htaccess rules force all requests to a maintenance page except when accessed from a specific IP (address removed).

I'm using this with Wordpress.

This seems to works fine for all front end pages, however for some reason all requests for wp-admin and root or domain without a URI are still getting redirected which means that the IP address excluded is unable to see the root or home page and instead receives the maintenance page.

RewriteEngine On
RewriteCond %{REMOTE_ADDR} !^xx\.xxx\.xxx\.xxx$
RewriteCond %{REQUEST_URI} !^maintenance$ [NC]
RewriteCond %{REQUEST_URI} !^\.(jpe?g?|png|gif)$ [NC]
RewriteRule ^(.*)$ maintenance [R=302,L]

Can anyone advise how I stop the root / requests without a URI / home page from being redirected ?

Have spent quite a few hours on this and I just can't see it. Hope someone can set me on the right track.





 2:16 am on Jan 28, 2013 (gmt 0)

You should return "503 Unavailable" during maintenance.

The 302 redirect is a disaster.

You should rewrite (that's internally rewrite, not externally redirect) those requests to a PHP script that delivers a 503 HEADER and the human readable error message.

.* is all pages including root. The ( and ) are unecessary when you're not re-using the capture. The ^ and $ are unecessary because .* matches the entire input.

RegEx pattern for NOT root is . or .+ or !^$ - pick one.


 4:18 am on Jan 28, 2013 (gmt 0)

You should rewrite (that's internally rewrite, not externally redirect) those requests to a PHP script that delivers a 503 HEADER and the human readable error message.

Can't you do it upfront in htaccess combined with your custom 503 page? Fine print (under #flag_r) [httpd.apache.org] says that you can attach any number to the R= flag, not just a redirect.

Tangential question:
RewriteCond %{REQUEST_URI} !^\.(jpe?g?|png|gif)$ [NC]
What's the reason for this exemption? Just to let search engines continue to pick up images, since they're unaffected by the reconstruction going on elsewhere?

Either way, seems like you'd do better to make it part of the Rule itself:

RewriteRule ^([^/.]+/)*([^/.]+\.html)?$ {et cetera}

Don't cut and paste: exact wording is off the top of my head. You may want to include css in the rule, since it's probably changing a bit too. So (?:css|html) or similar. If you've got a seriously overloaded server, all parentheses everywhere can be expressed as (?:blahblah) to make them non-capturing.


 8:20 am on Jan 28, 2013 (gmt 0)

Hi lucy24,

That's what I was hoping for. I've got a custom 503 page and I was looking to trigger the redirect under certain conditions as I want some parts of the site live and others redirecting.

OK, so I've modified the rewriterule [R=503,L]

No real reason for this actually: RewriteCond %{REQUEST_URI} !^\.(jpe?g?|png|gif)$ [NC]
I was playing around with conditions so its been removed.


Hi g1smd

I'd tried using . or .+ or !^$ and tested for this conditionally. Are you saying I should bee using it in the rewriterule ?

So I've now got

RewriteEngine On
RewriteCond %{REMOTE_ADDR} !^xx\.xxx\.xxx\.xxx$
RewriteCond %{REQUEST_URI} !^maintenance$ [NC]
RewriteRule !^$ maintenance [R=503,L]


 9:10 am on Jan 28, 2013 (gmt 0)

When using this...

RewriteCond %{REMOTE_ADDR} !^xx\.xxx\.xxx\.xxx$
RewriteCond %{REQUEST_URI} !^maintenance$ [NC]
RewriteRule .+ maintenance [R=503,L]

or if I use !^$ OR . in the RewriteRule and access site through a proxy (different IP) I'm still getting the page requested and not the maintenance page ?


 9:21 am on Jan 28, 2013 (gmt 0)

You'll need to add another condition to check the REMOTE_ADDR is not that of the proxy.


 9:58 am on Jan 28, 2013 (gmt 0)

I got this working with the following;

RewriteCond %{REQUEST_URI} !maintenance [NC]
RewriteCond %{REMOTE_ADDR} !xx\.xxx\.xxx\.xxx$
RewriteRule .? maintenance [R=503,L]

As my %{REMOTE_ADDR} condition is checking for NOT ! it only passes through if it does not match the IP.

Not sure why I would need to check for a proxy g1smd ? The point of the proxy (in this instance) was to mask the IP whilst I was checking that everybody else would be redirected apart from those accessing from the specific IP address. The proxy was for simulating a visitor from another IP.


 10:07 am on Jan 28, 2013 (gmt 0)

I misunderstood why you were accessing via proxy.

.? and .* match all pages including root.

. and .+ and !^$ match all pages not including root.


 10:23 am on Jan 28, 2013 (gmt 0)

For some reason when I accessed the site from the IP that was allowed to pass it was still redirecteding the root and wp-admin.

Now that I've changed the rewrite cond/rule to:

RewriteCond %{REQUEST_URI} !maintenance [NC]
RewriteCond %{REMOTE_ADDR} !xx\.xxx\.xxx\.xxx$
RewriteRule .? maintenance [R=503,L]

I don't have any problems g1smd ?


 10:28 am on Jan 28, 2013 (gmt 0)

RewriteRule .? maintenance [R=503,L]

Note that the "R=503" element is just mod_rewrite's wonky wording; you're not really redirecting. The target-- if any-- is ignored, the server hands out a 503 and humans get your custom 503 page. So you also need an ErrorDocument line pointing to the "maintenance" page.

If you don't want requests for the front page to get the 503, you may need to do the opposite of a normal index-redirect and say something like
(with surrounding syntax, of course). This is in case the request passed through mod_dir before it got to mod_rewrite. If this happens there would never be a request for / alone but always "index.html". I have been bitten by this one myself.

Oh, and you shouldn't need the [NC]. Since it's an internal request, there's no chance of it being mis-capitalized. Supposed someone explicitly asks for MaintenAncE and is allowed through? They'll end up getting your 404 page instead.


 10:56 am on Jan 28, 2013 (gmt 0)

What I'm trying to achieve is to be able to redirect any part of the site to a maintenance page (or vice versa) as each part is either being rebuilt or has been rebuilt.

Right now I want all pages for visitors (not equal to %{REMOTE_ADDR}) to be sent to a maintenance page and all pages requested from the %{REMOTE_ADDR} to be passed through.

When I use the following rules;

RewriteCond %{REQUEST_URI} !maintenance
RewriteCond %{REMOTE_ADDR} !xx\.xxx\.xxx\.xxx$
RewriteRule .? maintenance [R=503,L]

It works almost exactly as I need it, however if I now make a request for the maintenance page to view it from the %{REMOTE_ADDR} I would expect to be served that page, however I get redirect back to the front page ?

I think what you're saying lucy24 is that I need to test for THE_REQUEST ?

Would this work ?

RewriteCond %{THE_REQUEST} !/
RewriteCond %{REQUEST_URI} !maintenance
RewriteCond %{REMOTE_ADDR} !xx\.xxx\.xxx\.xxx$
RewriteRule !^$ maintenance [R=503,L]

I'm using a wordpress page "maintenance" as the custom 503 page.


 12:08 pm on Jan 28, 2013 (gmt 0)

As I'm using a wordpress page for my 503 I've modified the rewriterule;

RewriteRule .? maintenance [R=302,L] - which is a moved temporarily

On being redirected to the maintenance page the 503 header (Service Temporarily Unavailable) will then be output.

I now have control over the conditions that trigger the maintenance page.

RewriteCond %{REQUEST_URI} !maintenance [NC]
RewriteCond %{REMOTE_ADDR} !xx\.xxx\.xxx\.xxx$
RewriteRule .? maintenance [R=302,L]

Requests for the maintenace page from %{REQUEST_URI} are also being served OK.


 4:30 pm on Jan 28, 2013 (gmt 0)

Nope, looks like some strange goings on....I'm going to have to wait for DNS changes to settle down as I'm getting inconsistent results.


 9:35 am on Jan 29, 2013 (gmt 0)

Finally a stable and working outcome.

As my 503 error page is actually a wordpress page (themed) I've gone with the following that seems to be working.

RewriteCond %{REQUEST_FILENAME} !\.(gif|jpe?g|png|css|js)$ - design files not blocked ?
RewriteCond %{REQUEST_URI} !^maintenance?$ - exclude maintenance page itself
RewriteCond %{REMOTE_ADDR} !=xx.xxx.xxx.xxx - allow specific IP
RewriteCond %{HTTP:X-FORWARDED-FOR} !=xx.xxx.xxx.xxx- allow specific IP (load balanced)
RewriteRule ^(.*)$ maintenance/ [R=302,NC,L] - otherwise redirect

The error is sent on the wp themed page by ensuring that <?php die(); ?> is output after error content is displayed.

Not sure if I actually need the first line as the user is not requesting those files ?


 10:36 am on Jan 29, 2013 (gmt 0)

Returning 302 is the wrong response. You should not be redirecting requests to a different URL.

You should be returning the 503 at the originally requested URL.


 12:04 pm on Jan 29, 2013 (gmt 0)

Yes g1smd I understand. I've updated the rules and added the errodoc to htaccess.

RewriteRule ^(.*)$ maintenance/ [R=503,NC,L]


 12:22 am on Jan 30, 2013 (gmt 0)

Just to double-check that we're all on the same page haha

RewriteRule ^(.*)$ maintenance/ [R=503,NC,L]

In this Rule, the "maintenance/" element is purely for your own information. It is ignored by mod_rewrite because the number after "R=" is outside the 3xx range.

Oh and, ahem, the [NC] is utterly unnecessary since you're not looking for some specific text. The [L] is technically superfluous since anything outside of R=3xx carries an automatic [L], but will do no harm.


 12:45 am on Jan 30, 2013 (gmt 0)

After the various Conditions I use this rule:

RewriteRule .* /temp503.php [L]

where the first line of temp503.php uses the PHP HEADER directive to send the 503 response back to the browser and inform the "retry-after" value.

The remainder of the PHP script generates the human readable HTML page containing the details of why the site is offline.

The .* pattern matches all requested pages of the site, including root; replace .* with something more specific if necessary.


 8:32 am on Jan 30, 2013 (gmt 0)

Yes lucy24, thankyou for ensuring I tidy this up correctly.

So I would either;

ErrorDocument 503 /maintenance/
RewriteRule ^(.*)$ [R=503] - errordoc takes care of the page to be served

- should I still send the 503 header via the maintenance page itself (which I'm doing with PHP) ?


RewriteRule ^(.*)$ maintenance/ [L] - to send to the maintenance page and send the 503 with PHP

Using whatever pattern matches and rewrites to suit.


 9:14 am on Jan 30, 2013 (gmt 0)

Hmmm, the only way I get the correct result (503 header when requesting any page and the maintenance page served) is by using;

RewriteRule ^(.*)$ maintenance/ [R=503,L]

If I use (below) I get a 200 OK ?

RewriteRule ^(.*)$ [R=503]


 9:41 am on Jan 30, 2013 (gmt 0)

The last rule is missing a target, in this case a hyphen is used as placeholder, and the [L] flag.

See also msg:4540381.


 10:12 am on Jan 30, 2013 (gmt 0)

So, more like this for the last rule.

RewriteRule ^(.*)$ - [R=503] as lucy24 said the [L] is technically superfluous since anything outside of R=3xx carries an automatic [L] ?

I tested and it works fine.


 10:16 am on Jan 30, 2013 (gmt 0)

Since you're not re-using $1 there's no need to "capture" it. And since .* is greedy and matches "everything", there's no need for ^ or $ here.

^(.*)$ simplifies to .*

Yes, the [L] flag is not needed if the code is 4xx or 5xx, rather than 3xx. I forgot about that.


 10:44 am on Jan 30, 2013 (gmt 0)

Ah, yes g1smd that slims if further, thank you and lucy24

Global Options:
 top home search open messages active posts  

Home / Forums Index / Code, Content, and Presentation / Apache Web Server
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved