← Back to Apache Course | Chapter 7: Advanced | Lesson 1 of 4

Reverse Proxy

Running Apache as a reverse proxy means it's the only thing the public internet talks to directly, quietly forwarding requests behind the scenes to one or more backend application servers that never need to be exposed themselves.

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.

Warning: Without X-Forwarded-For, every request reaching the backend appears to come from the proxy's own address -- breaking anything on the backend that logs, rate-limits, or makes decisions based on client IP.

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

apacheconf
<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). #}

⚠️ This example can't run in the browser editor. Try it in your own local environment instead.

{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. 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.
  2. Using a plain ProxyPass for a WebSocket endpoint instead of mod_proxy_wstunnel, silently breaking real-time features that rely on it.
  3. 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:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.