title: Tips for debugging .htaccess rewrite rules
body: <p>Many posters have problems debugging their RewriteRule and RewriteCond statements within their <strong><code>.htaccess</code></strong> files.  Most of these are using a shared hosting service and therefore don't have access to the root server configuration. They cannot avoid using <code>.htaccess</code> files for rewriting and <em>cannot</em> enable a RewriteLogLevel&quot; as many respondents suggest.  Also there are many <code>.htaccess</code>-specific pitfalls and constraints are aren't covered well.  Setting up a local test LAMP stack involves too much of a learning curve for most.</p>
  <p>So my Q here is how would we recommend that they <em><strong>debug</strong></em> their rules <em>themselves</em>.  I provide a few suggestions below.  Other suggestions would be appreciated.</p>
  <ol>
  <li><p><strong>Understand that the mod_rewrite engine cycles through <code>.htaccess</code> files</strong>. The engine runs this loop:</p>
  <pre><code>do
    execute server and vhost rewrites (in the Apache Virtual Host Config)
    find the lowest &quot;Per Dir&quot; .htaccess file on the file path with rewrites enabled
    if found(.htaccess)
       execute .htaccess rewrites (in the user's directory)
  while rewrite occurred
  </code></pre>
  <p>So your rules will get executed repeatedly and if you change the URI path then it may end up executing other <code>.htaccess</code>files if they exist. So make sure that you terminate this loop, if necessary by adding extra <code>RewriteCond</code> to stop rules firing.  Also delete any lower level <code>.htaccess</code> rewrite rulesets unless explicitly intent to use multi-level rulesets.</p>
  </li>
  <li><p><strong>Make sure that the syntax of each Regexp is correct</strong> by testing against a set of test patterns to make sure that is a valid syntax and does what you intend with a fully range of test URIs.  See <a href="https://stackoverflow.com/questions/9153262/tips-for-debugging-htaccess-rewrite-rules/9261963#9261963">answer below</a> for more details.</p>
  </li>
  <li><p><strong>Build up your rules incrementally in a test directory.</strong>  You can make use of the &quot;execute the deepest <code>.htaccess</code> file on the path feature&quot; to set up a separate test directory (tree) and debug rulesets here without screwing up your main rules and stopping your site working.  You have to add them one at a time because this is the only way to localise failures to individual rules.</p>
  </li>
  <li><p><strong>Use a dummy script stub to dump out server and environment variables</strong>. (See <strong>Listing 2</strong>)If your app uses, say, <code>blog/index.php</code> then you can copy this into <code>test/blog/index.php</code> and use it to test out your blog rules in the <code>test</code> subdirectory.  You can also use environment variables to make sure that the rewrite engine in interpreting substitution strings correctly, e.g.</p>
  <pre><code>RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html]
  </code></pre>
  <p>and look for these <strong>REDIRECT_*</strong> variables in the phpinfo dump.  BTW, I used this one and discovered on my site that I had to use <code>%{ENV:DOCUMENT_ROOT_REAL}</code> instead.  In the case of redirector looping  <strong>REDIRECT_REDIRECT_*</strong> variables list the previous pass. Etc..</p>
  </li>
  <li><p><strong>Make sure that you don't get bitten by your browser caching incorrect 301 redirects</strong>.  See <a href="https://stackoverflow.com/questions/9153262/tips-for-debugging-htaccess-rewrite-rules/9261963#9204355">answer below</a>.  My thanks to <a href="https://stackoverflow.com/users/499472/ulrich-palha">Ulrich Palha</a> for this.</p>
  </li>
  <li><p>The rewrite engine seems sensitive to cascaded rules within an <code>.htaccess</code> context, (that is where a <code>RewriteRule</code> results in a substitution and this falls though to further rules), as I found bugs with internal sub-requests <a href="http://httpd.apache.org/docs/2.2/rewrite/flags.html#flag_n" rel="noreferrer">(1)</a>, and incorrect <strong>PATH_INFO</strong> processing which can often be prevents by use of the [NS], [L] and [PT] flags.</p>
  </li>
  </ol>
  <p>Any more comment or suggestions?</p>
  <h2>Listing 1 -- phpinfo</h2>
  <pre><code>&lt;?php phpinfo(INFO_ENVIRONMENT|INFO_VARIABLES);
  </code></pre>