How to Configure Apache ProxyPass to Exclude Static Files from Proxying to Jetty Backend


4 views

When setting up Apache as a reverse proxy for Jetty applications, developers often encounter unexpected 404 errors for static resources. The core issue lies in how ProxyPass ! directives interact with your directory structure and Location matching.

The configuration you provided shows a common misconception. The block with ProxyPass ! only works if:

  • Your static files are physically located in a /static/ subdirectory
  • The requests exactly match the Location path
  • No other directives override this exclusion

Here are three working approaches:

1. Filesystem-Based Exclusion

# Map static files directly to filesystem
Alias /static/ "/path/to/foo/static/"

    Require all granted
    Options -Indexes


# Proxy everything else
ProxyPass / http://localhost:8081/
ProxyPassReverse / http://localhost:8081/

2. Pattern-Based Exclusion

# Skip proxying for common static file extensions

    ProxyPass !

3. Hybrid Approach (Recommended)

# Physical path for static assets
AliasMatch "^/static/(.*)" "/path/to/foo/static/$1"

    Require all granted


# Proxy all non-static requests
ProxyPass / http://localhost:8081/ nocanon
ProxyPassReverse / http://localhost:8081/

# Additional exclusions

    ProxyPass http://localhost:8081/
    ProxyPassReverse http://localhost:8081/

Enable these Apache modules for troubleshooting:

LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule headers_module modules/mod_headers.so
LoadModule rewrite_module modules/mod_rewrite.so

Add logging to track proxy behavior:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy
CustomLog logs/proxy_access.log proxy
LogLevel debug

When configuring Apache as a reverse proxy for Jetty, many developers expect ProxyPass ! to completely bypass proxy processing for static files. However, there's more to it than meets the eye. Here's why your static files might still be routing to Jetty despite the exclusion rule.

The key misunderstanding lies in how Apache processes Location versus Directory directives. The /static/ Location block only matches requests that explicitly begin with "/static/" in the URL path.

# This ONLY matches /static/file.js but NOT /static-version/file.js
<Location /static/>
  ProxyPass !
</Location>

Here's a tested configuration that properly handles static files:

<VirtualHost *:80>
  ServerName foo.com
  DocumentRoot "/path/to/foo"

  # Static files configuration
  Alias /static/ "/path/to/foo/static/"
  <Directory "/path/to/foo/static">
    Options -Indexes
    AllowOverride None
    Require all granted
  </Directory>

  # Proxy configuration
  ProxyRequests Off
  ProxyPreserveHost On
  ProxyVia Off

  # Explicit static files exclusion
  <LocationMatch "\.(css|js|png|jpg|gif|ico|woff|woff2|ttf|svg)$">
    ProxyPass !
    Header set Cache-Control "max-age=31536000, public"
  </LocationMatch>

  # Main proxy pass
  <Location />
    ProxyPass http://localhost:8081/
    ProxyPassReverse http://localhost:8081/
  </Location>
</VirtualHost>

Case 1: Files in /static/ still proxy to Jetty
Solution: Add the Alias directive and ensure directory permissions

Case 2: Versioned static files (e.g., script-v2.js) get proxied
Solution: Use LocationMatch with regex pattern instead

Case 3: Browser caching issues
Solution: Add Cache-Control headers as shown above

For production environments, consider adding these enhancements:

# Enable HTTP/2 for static content
Protocols h2 http/1.1

# Gzip compression
AddOutputFilterByType DEFLATE text/css application/javascript

# ETag support
FileETag MTime Size

When troubleshooting, check these Apache logs:

# In your virtual host config
LogLevel debug
ErrorLog /var/log/apache2/foo-error.log
CustomLog /var/log/apache2/foo-access.log combined

Useful grep commands:

tail -f /var/log/apache2/foo-error.log | grep -i proxy
curl -I http://foo.com/static/test.js | grep -i "X-Proxy"