Apache Http Reverse Proxy

Using Apache HTTP as Reverse Proxy

What is a Reverse Proxy

A reverse proxy acts as a middle man to all incoming traffic. All incoming traffic first comes to the reverse proxy and from the proxy it is routed to the next component.

The below diagram shows the example of a reverse proxy in action

Reverse Proxy

The idea behind the above setup is to protect all internal servers from the external world. While this does present a Single point of Failure, it also provides many additional benefits as explained below.

Why use a Reverse Proxy

There are some common use cases for a reverse proxy

  • SSL termination
  • CORS protection
  • Load Balancing
  • Caching layer
  • Common compression for incoming and outgoing data

As evident from the above list, a large function of the reverse proxy architecture is to speed up the operations and enable quicker request reslution. Additionally in cases where you have multiple application (running on multiple ports), to the external world only 1 port is exposed.

Configuring Apache Httpd

Some important configuration is as below:

vi /etc/httpd/conf/httpd.conf

Listen 80
<VirtualHost *:80>
	SSLProxyEngine on
	ProxyPreserveHost On
	ProxyPass / https://localhost:8080/
	ProxyPassReverse / https://localhost:8080/
</VirtualHost>

vi /etc/httpd/conf.d/ssl.conf

Listen 443
<VirtualHost *:443>
	ServerName mysite.com
	SSLEngine on
	SSLCertificateFile "/location_to_file/cert.pem"
	SSLCertificateKeyFile "/location_to_file/key.pem"
	SSLProxyEngine on
	ProxyPreserveHost On
	ProxyPass / https://localhost:8080/
	ProxyPassReverse / https://localhost:8080/
</VirtualHo

Adding compression for static content

vi /etc/httpd/conf.modules.d/compression.conf

# Load the Gzipping module
LoadModule deflate_module modules/mod_deflate.so

# Add compression for the below content types
 
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE image/svg+xml

Reverse Proxying Web Sockets

Option #1:

Define a websocket proxy as below

<VirtualHost *:443>
    ServerName public-server
    ProxyPass /liveviewhandler/ ws://<backend-server>/liveviewhandler/
    ProxyPassReverse /liveviewhandler/ wss://<backend-server>/liveviewhandler/
    ProxyPass / https://<backend-server>/
    ProxyPassReverse / https://<backend-server>/
    ProxyRequests off
</VirtualHost>

The challenge with the above approach is that every URL must be uniquely identified as a websocket only URL

Option #2:

Use rewriting to identify if a request is for Websocket or not. If for websocket then proxy to backend.

<VirtualHost *:443>
    ServerName public-server
    RewriteEngine on
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule .* "wss://<backend-server>%{REQUEST_URI}" [P]
    ProxyPass / http://<backend-server>/
    ProxyPassReverse / http://<backend-server>/
    ProxyRequests off
</VirtualHost>

The advantage with the above approach is it identifies a websocket reqest and automatically proxies it.