Reverse Proxy
In this page:
Why Put Apache in Front of an App Server
Application servers like Gunicorn, uWSGI, or Node.js are good at running application code, but Apache is better at the things every production site needs anyway: terminating TLS, serving static files directly and efficiently, compressing responses, and centralizing logging -- all without the application itself needing to implement any of it.
The Core Directives, Revisited
As covered in the mod_proxy lesson, ProxyPass forwards matching requests to a backend address, and ProxyPassReverse rewrites Location/Set-Cookie headers in the response so redirects and cookies reference the public URL, not the backend's internal one. A reverse proxy setup is really just applying these two directives to the site's main traffic, not just one /api/ path.
Passing Along Real Client Information
Once Apache sits in front of the app, every request the backend sees appears to come from Apache's own IP (127.0.0.1), not the real visitor. ProxyPreserveHost On keeps the original Host header, and headers like X-Forwarded-For (the real client IP) and X-Forwarded-Proto (whether the original request was HTTP or HTTPS) need to be added so the backend application can still see the information it needs -- for things like IP-based rate limiting or generating correct HTTPS links.
WebSockets Through a Proxy
A plain HTTP proxy configuration doesn't handle WebSocket connections, which stay open and communicate bidirectionally rather than following the request/response pattern. mod_proxy_wstunnel, combined with a RewriteRule matching the Upgrade: websocket header, is needed to proxy WebSocket traffic correctly through Apache.
Example: A reverse proxy passing along real client info
<VirtualHost *:443>
ServerName example.com
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
ProxyPass "/" "http://127.0.0.1:8000/"
ProxyPassReverse "/" "http://127.0.0.1:8000/"
</VirtualHost>
{# Flagged by hand after confirming a runner can't handle this example
(a shell command / go.mod file stored as a TopicExample, a language
feature the configured runner version doesn't support, or output
that blows a runner's sandbox limit) -- see TopicExample.norun.
Never render the run button for these, regardless of language,
since it would just fail at execute_code (or worse, hang the
Judge0 queue on a submission that can never finish cleanly). #}
- Forgetting X-Forwarded-For/X-Forwarded-Proto, so the backend application can't tell the real client IP or whether the original connection was HTTPS.
- Using a plain ProxyPass for a WebSocket endpoint instead of mod_proxy_wstunnel, silently breaking real-time features that rely on it.
- Exposing the backend application server's port publicly in addition to proxying through Apache, giving attackers a second, unprotected way to reach it directly.
Chapter Quiz — Complete all 4 topics to unlock
0/4 topics done
Complete these topics first: