When dealing with complex URL rewriting scenarios in Apache, there are several ways to examine how your RewriteCond
and RewriteRule
directives are executing:
# The most important logging directive for mod_rewrite:
LogLevel alert rewrite:trace6
# In your virtual host configuration:
ServerName example.com
RewriteLog "/var/log/apache2/rewrite.log"
RewriteLogLevel 3
For Apache 2.4 and later, the recommended way to debug redirects is through the LogLevel
directive:
# Different trace levels provide varying detail:
# trace1 - Basic operation tracking
# trace3 - Includes rule matching details
# trace5 - Shows condition evaluation
# trace8 - Full internal processing details
LogLevel rewrite:trace5
Consider this rewrite scenario that's not behaving as expected:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^old\.example\.com$ [NC]
RewriteCond %{REQUEST_URI} !^/maintenance\.html$
RewriteRule ^(.*)$ https://new.example.com/$1 [R=301,L]
To debug this, you would:
- Set the log level as shown above
- Restart Apache
- Make test requests
- Check error logs (typically
/var/log/apache2/error.log
)
Sample log entries might look like:
[rewrite:trace2] [pid 12345] mod_rewrite.c(476): [client 192.168.1.1:12345] 192.168.1.1 - - [example.com/sid#7f8a3c0025b8][rid#7f8a3c0a70a0/initial] init rewrite engine with requested uri /test
[rewrite:trace1] [pid 12345] mod_rewrite.c(476): [client 192.168.1.1:12345] 192.168.1.1 - - [example.com/sid#7f8a3c0025b8][rid#7f8a3c0a70a0/initial] pass through /test
[rewrite:trace3] [pid 12345] mod_rewrite.c(476): [client 192.168.1.1:12345] 192.168.1.1 - - [example.com/sid#7f8a3c0025b8][rid#7f8a3c0a70a0/initial] [perdir /var/www/html/] applying pattern '^(.*)$' to uri '/test'
For tracking redirect destinations, you can create a custom log format:
LogFormat "%h %l %u %t \"%r\" %>s %{REDIRECT_URL}e" redirect_log
CustomLog /var/log/apache2/redirect.log redirect_log
- Missing log entries? Ensure your LogLevel directive is in the correct virtual host or server config section
- Too much noise? Start with trace3 and increase only when needed
- Logs too verbose? Use grep to filter:
grep "mod_rewrite" error.log
When complex redirect chains aren't behaving as expected, Apache provides multiple logging mechanisms to trace the rewrite execution flow:
- ErrorLog: Set
LogLevel alert rewrite:trace6
in httpd.conf for detailed rewrite debugging - CustomLog: Add
%{REDIRECT_STATUS}e
and%{REDIRECT_URL}e
variables to your log format - RewriteLog (deprecated in 2.4+): Older method using
RewriteLog "/path/to/rewrite.log"
Here's a complete virtual host setup with enhanced rewrite logging:
<VirtualHost *:80>
ServerName example.com
LogLevel warn rewrite:trace3
ErrorLog /var/log/apache2/rewrite_error.log
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/legacy/(.*)$ [NC]
RewriteRule ^(.*)$ https://newserver.com/migrated/%1 [R=301,L]
</IfModule>
CustomLog /var/log/apache2/rewrite_access.log combined
</VirtualHost>
A sample debug entry showing rewrite progression:
[rewrite:trace3] applying pattern '^(.*)$' to uri '/legacy/page.html'
[rewrite:trace1] pass through /legacy/page.html
[rewrite:trace3] applying pattern '^(.*)$' to uri '/legacy/page.html'
[rewrite:trace2] rewrite '/legacy/page.html' -> 'https://newserver.com/migrated/page.html'
[rewrite:trace2] forcing redirect with https://newserver.com/migrated/page.html
[rewrite:trace1] escaping https://newserver.com/migrated/page.html for redirect
For multi-server redirect scenarios, add these diagnostic rules before your main ruleset:
RewriteCond %{QUERY_STRING} ^debug=1$ [NC]
RewriteRule ^ - [E=rewrite_debug:1]
RewriteCond %{ENV:rewrite_debug} ^1$
RewriteRule ^ - [E=ORIGINAL_URI:%{REQUEST_URI},E=REDIRECT_TARGET:https://newserver.com%{REQUEST_URI}]
This creates environment variables that can be logged using %{ORIGINAL_URI}e
and %{REDIRECT_TARGET}e
in your CustomLog format.