Webmasters Stack Exchange is a question and answer site for pro webmasters. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

On the server, I have a file (on the filesystem) called page.html, which I want to be accessed as site.com/page So if someone goes to site.com/page.html, it should 301 redirect to site.com/page

I've seen rewrite rules that will handle rewriting /page -> /page.html internally, but forcing it to 301 redirect /page.html -> /page as well causes a redirect loop for me.

The END flag looks like it can be used to do what I want, but it is not yet supported.

I've also tried using ENV as follows:

RewriteRule ^page$ /page.html [L,E=END:1]
RewriteCond %{ENV:END} !1
RewriteRule ^page.html$ /page [R=301,L]

But that results in a redirect loop as well.

share|improve this question
As it should. I do not understand what you want- to redirect a page to a directory then the directory back to the original page does not make sense to me. – closetnoc Aug 29 '14 at 4:02
@closetnoc The question has since been clarified a bit; the OP appears to be looking for help with his rewrite rule to remove the file extension, but the current one results in a redirect loop (which is a common problem when removing extensions). – dan Aug 29 '14 at 13:16
If you change your line to RewriteCond %{ENV:REDIRECT_END} !1 it should work for you. mod_rewrite renames the environment variable out from under you so you have to set it with one name, and read it with another. – Stephen Ostermiller Aug 29 '14 at 13:46
up vote 2 down vote accepted

I asked this same question on StackOverflow. To get it to work properly, you have to use environment variables:

RewriteRule ^page$ /page.html [L,E=LOOP:1]
RewriteCond %{ENV:REDIRECT_LOOP} !1
RewriteRule ^page.html$ /page [R=301,L]

This is because mod_rewrite does multiple passes through your rules. During the first pass, it sets the environment variable. During the second pass, it prepends the variable with the REDIRECT_ prefix, so you have to read it as REDIRECT_LOOP.

share|improve this answer
+1, this may be cleaner than my solution. – Ilmari Karonen Aug 29 '14 at 13:49

The problem is that, when you use mod_rewrite in an .htaccess file or a <Directory> section, every successful RewriteRule — even an internal one — causes the request to be restarted internally, and thus the whole rewrite ruleset to be reprocessed.

Thus, what's happening is that, when the user visits /page, your internal RewriteRule matches and rewrites the URL to /page.html. But that makes Apache restart the request processing and run your ruleset again, causing the external rewrite rule to match and trigger a 301 redirect back to /page.

A quick and dirty (but effective!) fix is to make your internal rewrite rule append a dummy parameter like redirect=no to the URL, and check for that parameter in the external rewrite rule. Here's an example based on this answer I wrote for a similar question on Stack Overflow:

RewriteEngine On
RewriteBase /

# Externally rewrite page.html -> page, unless query includes redirect=no:
RewriteCond %{QUERY_STRING} !(^|&)redirect=no(&|$) 
RewriteRule ^(page)\.html$ /$1  [NS,R=301,L] 

# Internally rewrite page -> page.html, add redirect=no to query:
RewriteRule ^(page)$ $1.html?redirect=no [NS,QSA]

(Of course, feel free to replace redirect=no with something else if it conflicts with an actual URL parameter you might be using.)

share|improve this answer
Thanks for your answer! That's the workaround that I had been using in the meanwhile. – arcyqwerty Aug 29 '14 at 18:43

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.