When implementing a failover mechanism for reverse-proxied content in Apache HTTPD, many developers encounter the notorious "No protocol handler was valid for the URL" error. This typically occurs when configuring mod_proxy_balancer
with static backup content, especially after mirroring dynamic sites using tools like wget
.
Here's a complete configuration that demonstrates both the problematic setup and the solution:
# Base configuration
DocumentRoot /var/www/www.example.com/htdocs
# Proxy settings
ProxyRequests Off
ProxyPreserveHost On
# Balancer configuration
ProxyPass "/site/" "balancer://cms"
ProxyPassReverse "/site/" "balancer://cms"
ProxyPassReverse "/site/" "http://ip-10-1-1-229.ec2.internal/site/"
# Balancer members
<Proxy "balancer://cms">
BalancerMember "http://ip-10-1-1-229.ec2.internal/site/" loadfactor=1
BalancerMember "file:///var/www/www.example.com/htdocs/site-backup/" loadfactor=10 status=+H
</Proxy>
# Directory permissions
<Directory "/var/www/www.example.com/htdocs/site-backup">
Require all granted
Options Indexes FollowSymLinks
DirectoryIndex index.html
</Directory>
The root cause lies in how Apache handles different protocol handlers:
- Protocol Handler Mismatch: The error suggests Apache can't find a suitable module to handle the specified protocol. For static files, we need
mod_proxy_file
(though it's not standard), or better yet, use thefile://
protocol directly. - Path Resolution: The double
/site/
in URLs indicates path mapping issues. The solution involves either:- Adjusting the DocumentRoot to include the full static content path
- Using proper RewriteRules to handle path translations
Here's the corrected configuration that properly handles static content fallback:
# Revised balancer configuration
<Proxy "balancer://cms">
# Primary dynamic server
BalancerMember "http://ip-10-1-1-229.ec2.internal/site/" loadfactor=1
# Static backup using file:// protocol
BalancerMember "file:///var/www/www.example.com/htdocs/site-backup/www.example.com/site/"
loadfactor=10
status=+H
retry=5
</Proxy>
# Additional rewrite rules if needed
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/site/(.*)
RewriteCond %{DOCUMENT_ROOT}/site-backup/www.example.com/site/$1 -f
RewriteRule ^ /site-backup/www.example.com/site/$1 [L]
To verify the setup works:
# Check loaded modules
apachectl -M | grep proxy
# Test URL resolution
curl -v http://localhost/site/sites/default/files/foo.png
# Verify file permissions
namei -l /var/www/www.example.com/htdocs/site-backup/www.example.com/site/sites/default/files/foo.png
When using static fallback content:
- Set appropriate caching headers for static resources
- Consider using
mod_cache
for frequently accessed content - Monitor the
balancer://
worker status using/balancer-manager
For more complex scenarios:
# Using mod_rewrite for conditional fallback
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/site/(.*)
RewriteCond %{HTTP_HOST} backup=1 [OR]
RewriteCond expr "! -R '192.168.1.0/24'"
RewriteRule ^ /site-backup/www.example.com/site%{REQUEST_URI} [L]
When setting up a failover system with Apache's mod_proxy_balancer
, developers often encounter the "No protocol handler valid for the URL" error. This typically occurs when attempting to serve static content through a reverse proxy configuration while implementing a CMS failover mechanism.
The error primarily stems from two common issues:
1. Missing or incorrectly configured proxy modules
2. URL path mismatches between the proxy configuration and filesystem structure
In our specific case, the problem manifests when:
- The browser requests resources like CSS/images from /site/sites/default/files/
- The physical files exist in /var/www/www.example.com/htdocs/site-backup/www.example.com/site/sites/default/files/
- The proxy balancer fails to properly translate the URL paths
Here's a corrected configuration that addresses both the protocol handler error and path translation:
DocumentRoot /var/www/www.example.com/htdocs
ProxyRequests Off
ProxyPreserveHost On
# Main proxy configuration
ProxyPass "/site/" "balancer://cms"
ProxyPassReverse "/site/" "balancer://cms"
ProxyPassReverse "/site/" "http://ip-10-1-1-229.ec2.internal/site/"
# Balancer configuration
<Proxy "balancer://cms">
# Primary CMS (commented for testing)
# BalancerMember "http://ip-10-1-1-229.ec2.internal/site/" loadfactor=1
# Local static backup with corrected path mapping
BalancerMember "file:///var/www/www.example.com/htdocs/site-backup/www.example.com" loadfactor=10 status=+H
</Proxy>
# Alias for static content
Alias "/site/sites/default/files/" "/var/www/www.example.com/htdocs/site-backup/www.example.com/site/sites/default/files/"
<Directory "/var/www/www.example.com/htdocs/site-backup">
Require all granted
Options Indexes FollowSymLinks
DirectoryIndex index.html
</Directory>
1. Protocol Specification:
Changed from "http://127.0.0.1/..." to "file:///..." for direct filesystem access
2. Path Alignment:
Added Alias directive to properly map URL paths to filesystem paths
3. Permission Updates:
Modernized from Order/Allow to Require all granted
To confirm the solution works:
1. Restart Apache: sudo apachectl graceful
2. Test with curl: curl -I http://test.example.com/site/sites/default/files/foo.png
3. Check error logs: tail -f /var/log/apache2/error.log
For production environments, consider adding these enhancements:
# Cache control for static assets
<LocationMatch "/site/sites/default/files/.*\.(png|jpg|css|js)$">
Header set Cache-Control "max-age=86400, public"
</LocationMatch>
# Error handling
ErrorDocument 502 /site-maintenance.html
ErrorDocument 503 /site-maintenance.html
The complete solution addresses both the immediate protocol handler error and provides a robust failover mechanism while maintaining proper URL mapping for all resources.