How to Fix URL Rewrite Before ProxyPass in Apache for Application Path Migration


4 views

When migrating applications behind reverse proxies, path handling often causes headaches. In this case, we have:

  • Original app running at localhost:10001
  • Need to serve it under /ds path
  • Hardcoded script references at /scripts that must transparently map to /ds/scripts

The configuration attempt had two key issues:

RewriteRule /^scripts/(.*)$ /ds/scripts/$1 [L,PT]
  1. The ^ anchor in the pattern won't work in per-directory context (inside VirtualHost)
  2. The rule needs proper flags for proxy integration

Here's the corrected VirtualHost setup:

<VirtualHost *:80>
    ServerName hostname.example.com
    
    # Enable rewrite engine
    RewriteEngine On
    
    # Catch script requests before proxying
    RewriteCond %{REQUEST_URI} ^/scripts/ [NC]
    RewriteRule ^/scripts/(.*) /ds/scripts/$1 [PT,L]
    
    # Proxy configuration
    ProxyPass /ds/ http://127.0.0.1:10001/
    ProxyPassReverse /ds/ http://127.0.0.1:10001/
    
    # Optional: Prevent direct access to backend
    ProxyPass / http://127.0.0.1:10001/ !
</VirtualHost>

RewriteCond: The condition ensures we only rewrite actual script paths

[PT] flag: Passes the rewritten URI through to subsequent processing (needed for ProxyPass)

[L] flag: Makes this the last rule if it matches

ProxyPass ! directive: Prevents direct backend access (security best practice)

Verify with curl commands:

# Should proxy to backend
curl -I http://hostname/ds/

# Should rewrite and proxy
curl -I http://hostname/scripts/main.js

# Should return 403 (blocked by ProxyPass !)
curl -I http://hostname/

For simpler cases, you might prefer:

<Location /scripts>
    ProxyPass http://127.0.0.1:10001/ds/scripts
    ProxyPassReverse http://127.0.0.1:10001/ds/scripts
</Location>

Enable verbose logging in httpd.conf:

LogLevel debug
RewriteLog "/var/log/apache2/rewrite.log"
RewriteLogLevel 3

Check for common pitfalls:

  • Ensure mod_rewrite and mod_proxy are loaded
  • Verify DocumentRoot isn't interfering
  • Check for conflicting .htaccess files

When setting up a reverse proxy for an application running on port 10001, we need to serve it under /ds path while handling hardcoded script references to /scripts. The challenge is to rewrite /scripts requests to /ds/scripts before they reach the proxied application.

Here's the initial VirtualHost configuration that didn't work as expected:

<VirtualHost *:80>
    RewriteEngine on
    RewriteRule /^scripts/(.*)$ /ds/scripts/$1 [L,PT]   
    
    ProxyPass /ds/ http://127.0.0.1:10001/
    ProxyPassReverse /ds/ http://127.0.0.1:10001/
</VirtualHost>

The main problems with the initial configuration are:

  1. The ^ anchor in the RewriteRule pattern is incorrect - it should not include the leading slash
  2. The PT (passthrough) flag is appropriate, but the pattern matching needs adjustment
  3. The rewrite rule should come before the ProxyPass directives

Here's the corrected configuration:

<VirtualHost *:80>
    ServerName hostname
    
    RewriteEngine On
    RewriteRule ^/scripts/(.*) /ds/scripts/$1 [PT]
    
    ProxyPass /ds/ http://localhost:10001/
    ProxyPassReverse /ds/ http://localhost:10001/
    
    # Optional: Handle requests to /scripts without trailing slash
    RewriteRule ^/scripts$ /ds/scripts/ [R=301,L]
</VirtualHost>
  • The ^/scripts/(.*) pattern correctly matches requests starting with /scripts/
  • [PT] flag ensures the rewritten URL is passed to the next processing phase (ProxyPass)
  • The order of directives is crucial - RewriteRules must come before ProxyPass
  • ProxyPassReverse handles redirects from the backend application

After implementing these changes, test with:

curl -I http://hostname/scripts/somefile.js
curl -I http://hostname/ds/scripts/somefile.js

Both should return the same content from your backend application.

For more complex scenarios, you might need:

# Handle various script extensions
RewriteRule ^/scripts/(.*\.(js|css|png))$ /ds/scripts/$1 [PT]

# Exclude certain paths from rewriting
RewriteCond %{REQUEST_URI} !^/scripts/excluded/
RewriteRule ^/scripts/(.*) /ds/scripts/$1 [PT]

Enable rewrite logging for troubleshooting:

RewriteLog "/var/log/apache2/rewrite.log"
RewriteLogLevel 3

Remember to turn this off in production environments.