When setting up Apache as a reverse proxy for Karaf-hosted applications (specifically Jetty servlets), we frequently encounter the need to:
- Hide the application context path (/jellyfish in this case)
- Maintain clean URLs at the proxy level
- Handle redirects properly without URL duplication
The current setup with ProxyPassMatch ^/(.*) http://granny-server:8181/jellyfish/$1
causes double-path issues because:
1. Initial request: /login
2. Proxy adds /jellyfish prefix → /jellyfish/login
3. Jetty responds with redirect containing full path /jellyfish/login
4. Proxy prepends another /jellyfish → /jellyfish/jellyfish/login
Here's a configuration that properly handles path manipulation:
<VirtualHost *:80>
ServerName web-server
# Essential proxy settings
ProxyRequests Off
ProxyPreserveHost On
ProxyVia On
# Local assets exclusion
Alias /images/ "/var/www/images/"
ProxyPass /images !
# Main proxy configuration
ProxyPass / http://app-server:8181/jellyfish/
ProxyPassReverse / http://app-server:8181/jellyfish/
# Special handling for redirects
Header edit Location ^http://app-server:8181/jellyfish/(.*)$ http://web-server/$1
# Security hardening
<Proxy *>
Require all granted
Allow from all
</Proxy>
# Additional headers if needed
RequestHeader set X-Forwarded-Proto "http"
RequestHeader set X-Forwarded-Port "80"
</VirtualHost>
1. ProxyPass with Trailing Slash:
The trailing slash in ProxyPass / http://app-server:8181/jellyfish/
ensures proper path concatenation.
2. Header Editing:
The Header edit Location
directive modifies redirect headers coming from the backend to maintain clean frontend URLs.
For cases requiring more complex routing:
RewriteEngine On
# Exclude static resources
RewriteCond %{REQUEST_URI} !^/images/.*$
# Proxy all other requests
RewriteRule ^/(.*)$ http://app-server:8181/jellyfish/$1 [P]
# Fix redirect headers
ProxyPassReverse / http://app-server:8181/jellyfish/
ProxyPassReverse / http://web-server/
After implementing, verify with:
curl -v http://web-server/login
(check Location headers)apachectl configtest
- Browser testing with developer tools open
- Double slashes in URLs - always include/exclude trailing slashes consistently
- SSL termination - remember to set X-Forwarded-Proto when using HTTPS
- WebSocket support - may require additional proxy parameters
When implementing Apache as a reverse proxy for Karaf-hosted applications, we often need to clean up URLs by removing application context paths. The specific challenge arises when:
- The backend application serves content under
/jellyfish
path - We want public URLs to appear as root-relative (
/login
instead of/jellyfish/login
) - Proxy configurations accidentally duplicate the path component
The error messages showing /jellyfish/jellyfish/home
indicate the path is being appended twice. This happens because:
ProxyPassMatch ^/(.*) http://granny-server:8181/jellyfish/$1
ProxyPassReverse / http://granny-server:8181/jellyfish
The ProxyPassMatch
adds jellyfish
to the path, then the backend application likely redirects with another jellyfish
prefix, creating the duplicate.
Here's a tested solution that properly handles path rewriting:
<VirtualHost *:80>
ServerName web-server
RewriteEngine On
# Security rule to prevent malicious proxy attempts
RewriteCond %{REQUEST_URI} !^/
RewriteRule .* - [R=400,L]
# Exclude static assets from proxying
ProxyPass /images !
Alias /images/ "/var/www/images/"
# Main proxy configuration
ProxyPass / http://app-server:8181/jellyfish/
ProxyPassReverse / http://app-server:8181/jellyfish/
# Handle redirects from the backend
ProxyPassReverseCookiePath /jellyfish /
# Required for proper host header handling
ProxyPreserveHost On
<Directory "/var/www/images">
Options Indexes MultiViews FollowSymLinks
Require all granted
</Directory>
</VirtualHost>
Path Handling: The trailing slashes in both ProxyPass
and ProxyPassReverse
are critical for proper path resolution.
Cookie Path Adjustment: ProxyPassReverseCookiePath
ensures session cookies work correctly when paths are rewritten.
Alternative Using mod_rewrite: For more complex scenarios, you could use:
RewriteRule ^/(.*)$ http://app-server:8181/jellyfish/$1 [P]
ProxyPassReverse / http://app-server:8181/jellyfish
- Enable
LogLevel debug
temporarily to trace rewrite/proxy behavior - Check both Apache access logs and backend application logs
- Test with
curl -v
to observe redirects and headers - Verify the backend isn't generating absolute URLs with the context path