Apache2: 400 Bad Request with Rewrite Rules, nothing in error log?

Solution 1:

For complicated mod_rewrite rules, it's a good idea to log the sequence of events to see what's happening. Do this using RewriteLog, and crank up the RewriteLogLevel to see the details.

mod_rewrite is very flexible and one can do many things with the rewrite rules, and is also quite complicated. An outsider will have trouble debugging your rules without seeing the broader context. The best thing you can do debug it on your own. Watch the logs in one window while you experiment with configuration changes in a second window. Make a small change, save the file, reload apache and hit the URL again. Repeat.

Here's a good description of RewriteLog from the Apache manual:

Rewrite Log

When using the powerful and complex features of mod_rewrite, it is almost always necessary to use the RewriteLog to help in debugging. This log file produces a detailed analysis of how the rewriting engine transforms requests. The level of detail is controlled by the RewriteLogLevel directive.

Solution 2:

Your substitution in <virtualhost> context uses a non-absolute URL. You can't do this outside of Directory/htaccess context.

Solution 3:

A few other notes, which became a bit too large to be contained in a mere comment:

RewriteCond $1 works, but it's quite dangerous and brittle. In particular, you could easily have rewritten the RewriteRule so as to disable the functionality of that RewriteCond altogether, and you'd never know you had. The use of %{REQUEST_URI} is recommended as a solution, à la RewriteCond %{REQUEST_URI} ^/(index\.php|resources|robots\.txt).

Next issue: these two lines:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

are not functional as presented. They either need to be placed inside a <Directory> stanza, or modified to use the look-ahead macros (e.g. RewriteCond %{LA-U:REQUEST_FILENAME} !-f).

The actual cause of you needing to remove the / is that .htaccess strips off the leading / from the first argument of RewriteRule, whereas it's delivered with / intact to RewriteRules in httpd.conf (or its Included files), which is something important to remember in case you ever try to move this rule back into a .htaccess. You can rework the Rule to be .htaccess/httpd.conf-agnostic by doing something like RewriteRule ^/?(.*)$ index.php/$1 [L,QSA].

One last note: as you can see in the rule, above, you don't need to escape the / with a backslash.