When setting up Apache as a reverse proxy for Tomcat with SSL, many developers encounter the frustrating scenario where direct access to the backend (https://host.example.org:8443) works fine, but the proxied connection (https://host.example.org) fails unexpectedly. The symptoms typically include:
# Apache error.log shows:
proxy: no HTTP 0.9 request (with no host line) on incoming request...
# Tomcat access.log shows corrupted request:
"?O^A^C / HTTP/1.1" 302
The core issue stems from SSL protocol handling between Apache's mod_proxy and the backend server. When SSLProxyEngine is enabled, Apache needs additional configuration to properly terminate SSL and forward requests to the backend.
Here's a complete VirtualHost configuration that resolves the SSL proxy issues:
<VirtualHost *:443>
ServerName host.example.org
SSLEngine On
SSLProxyEngine On
SSLCertificateFile /path/to/cert.pem
SSLCertificateKeyFile /path/to/key.pem
# Important SSL proxy settings
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
# Proxy configuration
ProxyRequests Off
ProxyPreserveHost On
ProxyVia On
RequestHeader set X-Forwarded-Proto "https"
# The crucial ProxyPass directive
ProxyPass / https://localhost:8443/ retry=0 timeout=30
ProxyPassReverse / https://localhost:8443/
# Logging
ErrorLog ${APACHE_LOG_DIR}/ssl_proxy_error.log
CustomLog ${APACHE_LOG_DIR}/ssl_proxy_access.log combined
</VirtualHost>
SSLProxyVerify none: Disables certificate verification between Apache and Tomcat when they're on the same host
ProxyPreserveHost On: Maintains the original host header
RequestHeader set X-Forwarded-Proto "https": Informs Tomcat about the original protocol
For complete solution, ensure your Tomcat's server.xml includes proper SSL connector:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="/path/to/keystore.jks"
keystorePass="password"
clientAuth="false" sslProtocol="TLS"
proxyName="host.example.org" proxyPort="443"/>
If issues persist, try these diagnostic steps:
1. Test with curl -v https://host.example.org
2. Check both Apache and Tomcat logs simultaneously
3. Temporarily disable firewall to rule out connectivity issues
4. Verify time synchronization between servers
Remember to restart Apache after configuration changes:
sudo systemctl restart apache2
When configuring Apache as a reverse proxy with SSL termination for backend applications (like Tomcat running on different ports), you might encounter connection issues where:
- The direct backend URL (e.g., https://host.example.org:8443) works
- The proxied SSL URL (https://host.example.org) fails with connection interruption
- Apache error logs show "proxy: no HTTP 0.9 request" warnings
- Backend access logs display garbled request methods (e.g., "?O^A^C")
The key problems in the original configuration are:
- Missing SSL certificate configuration for the VirtualHost
- Potential SSL protocol mismatch between Apache and backend
- Improper ProxyPass directive for HTTPS backend
Here's a corrected VirtualHost configuration that handles SSL proxying properly:
<VirtualHost 1.2.3.4:443>
ServerName host.example.org
# SSL Configuration
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite HIGH:!aNULL:!MD5
SSLCertificateFile /etc/ssl/certs/example.org.crt
SSLCertificateKeyFile /etc/ssl/private/example.org.key
SSLCertificateChainFile /etc/ssl/certs/example.org.ca-bundle
# Proxy Configuration
SSLProxyEngine On
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / https://localhost:8443/
ProxyPassReverse / https://localhost:8443/
# Required headers for proper backend communication
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
</VirtualHost>
1. SSL Directives: Essential for the frontend SSL termination
2. SSLProxy Settings: Controls how Apache handles SSL to the backend server
3. Header Modifications: Ensures the backend application receives correct protocol information
If the issue persists:
- Verify SELinux/apparmor isn't blocking proxy connections
- Check Apache modules are properly loaded:
a2enmod ssl
a2enmod proxy
a2enmod proxy_http
a2enmod headers
3. Test backend connectivity independently:
curl -vk https://localhost:8443/
For applications requiring WebSockets or special protocols:
<Location />
ProxyPass wss://localhost:8443/
ProxyPassReverse wss://localhost:8443/
ProxyPassReverseCookieDomain localhost host.example.org
</Location>