A reverse proxy is a type of proxy that accepts HTTP (S) requests and transparently distributes them to one or more back-end servers. Reverse proxies are useful because many modern web applications handle incoming HTTP requests using backend application servers do not need to be directly accessible to users and often only support basic HTTP functionality.
You can use a reverse proxy to prevent these core application servers from directly accessing. It can also be used to load balance incoming requests across multiple different application servers, increasing performance at scale and providing fault tolerance. It can fill the gaps with application server features that it doesn’t offer, such as caching, compression, or SSL encryption.
In this tutorial, you will configure Apache as your primary reverse proxy using the extension
mod_proxy to redirect incoming connections to one or more internal servers running on the same network. This tutorial uses a simple backend written in Flask web framework, but you can use any data server you prefer.
Following this tutorial, you will need:
- One Debian 8 server with initial server setup.
- Apache 2 installed on a server by following the guide how to install Linux, Apache, MySQL, PHP (LAMP) on Debian 8.
Step 1 – Including Required Apache Modules
Apache has many modules bundled with it that are available but not included in a new installation. First, we need to include the ones that we will be using in this tutorial.
The module we need is
mod_proxy and some of its add-on modules that extend its functionality to support various network protocols. Specifically, we will use:
mod_proxy, the main proxy module Apache module for redirecting connections; it allows Apache to act as a gateway to the main application servers.
mod_proxy_httpwhich adds support for proxying HTTP connections.
mod_lbmethod_byrequests, adds new load balancing functionality for multiple back-end servers.
To enable these four modules, you must run the following commands in sequence.
sudo a2enmod proxy sudo a2enmod proxy_http sudo a2enmod proxy_balancer sudo a2enmod lbmethod_byrequests
Restart Apache for these changes to take effect.
sudo systemctl restart apache2
Apache is now ready to act as a reverse proxy for HTTP requests. In the next (optional) step, we will create the two most basic back-end servers. This will help us verify that the configuration is working correctly, but if you already have your own backend application (s), you can skip to step 3.
Step 2 – Creating Internal Test Servers
Running some simple backend servers is an easy way to check that your Apache configuration is working as expected. Here we will make two test servers that respond to HTTP requests by printing a line of text. One server will say ‘Hello World! and the other will say ‘AndreyEx world! ,
Note In non-test installations, Backend servers generally return the same content type. However, for this test in particular, the two servers return different messages, making it easy to verify that the load balancer is using both.
Flask is a Python microframework for building web applications. We are using Flask to build test servers as the main application only requires a few lines of code. You don’t need to know Python to set them up.
Updating the package list first.
sudo apt-get update
Then install pip, the recommended Python package manager.
sudo apt-get -y install python3-pip
Use pip to install Flask.
sudo pip3 install flask
Now that all the prerequisites are installed, start by creating a new file that will contain the code for the first backend server in the current user’s home directory.
Copy the following code to a file and then save and close it.
~ / Backend1.py
from flask import Flask app = Flask(__name__) @app.route("https://andreyex.ru/") def home(): return 'Hello world!'
The first two lines of initialization of the Flask framework. There is one function,
home()which returns a string of text (
home() functions tells Flask to use
home()‘s return value as a response to HTTP requests aimed at
/application root URL.
The second backend server is exactly the same as the first except returning a different line of text, so start by duplicating the first file.
cp ~/backend1.py ~/backend2.py
Open the newly copied file.
Change the message to be returned from Hello World! at AndreyEx world! And then save and close the file.
~ / Backend2.py
from flask import Flask app = Flask(__name__) @app.route("https://andreyex.ru/") def home(): return 'AndreyEx world!'
Use the following command to start the first background server on the port
8080… This also redirects Flask output to
FLASK_APP=~/backend1.py flask run --port=8080 >/dev/null 2>&1 &
Here we preceded the command
flaskby setting the environment variable
FLASK_APP on the same line. Environment variables are a convenient way to pass information to processes that are spawned from the shell.
In this case, using the environment variable ensures that the parameter is applicable only to the running command and will not remain available after that, as we will pass another filename in the same way, type the command
flaskto start the second server
Similarly, use this command to start a second server on port
8081… Note the different meaning for the environment variable
FLASK_APP=~/backend2.py flask run --port=8081 >/dev/null 2>&1 &
You can check that both servers are running using
curl… Testing the first server:
This will output Hello World! in the terminal. Checking the second server:
This will output AndreyEx world!
Note To close both test servers after you no longer need them, and when you are done with this tutorial, you can simply execute killall flask.
In the next step, we will modify the Apache config file to enable it to be used as reverse proxy server on Debian 8…
Step 3 – Change the default configuration. Enabling reverse proxy
In this section, we will configure the default Apache virtual host to serve as a reverse proxy for a single backend server or load-balanced array of backend servers.
In this tutorial, we apply the settings at the virtual host level. With the default Apache installation, there is only one enabled, the default virtual host. However, you can use all of these configuration snippets in other virtual hosts.
If your server is running Apache as an HTTP and HTTPS server, your reverse proxy configuration must be hosted on both the HTTP and HTTPS virtual hosts.
Open the default Apache config file using
nano or your favorite text editor.
sudo nano /etc/apache2/sites-available/000-default.conf
Inside this file you will find a block
<VirtualHost *:80>starting from the first line. The first example below shows how to configure this reverse proxy block for one backend server, and the second sets up load balancing the reverse proxy for multiple backend servers.
Example 1 – Reverse proxying a server
Replace all content inside a block
VirtualHost with the following, your config file should look like this:
<VirtualHost *:80> ProxyPreserveHost On ProxyPass / http://127.0.0.1:8080/ ProxyPassReverse / http://127.0.0.1:8080/ </VirtualHost>
If you followed along with servers for example in step 2, use
127.0.0.1:8080 as written in the block above. If you have your own application servers, use their addresses.
There are three directives here:
ProxyPreserveHostmakes Apache pass the original
Hostheader to the internal server. This is useful as it makes the backend server a conscious address used to access the application.
ProxyPassmain directive for proxy configuration. In this case, it indicates that everything in the root URL (
/) must be mapped to the internal server at the specified address. For example, if Apache receives a request for
/example, it will connect and return a response to the original client.
ProxyPassReversemust have the same configuration as
ProxyPass… This tells Apache to change the response headers from the backend server. This ensures that if the backend server returns a location redirect header, the client browser will be redirected to the proxy server address and not the backend server address, which will not work as intended.
Restart Apache for the changes to take effect.
sudo systemctl restart apache2
Now if you access http: // your_server_ip through a web browser, you will see the backend server response instead of the standard Apache welcome page. If you followed the instructions in Step 2, then you will see Hello World!
Example 2 – Load Balancing Multiple Backend Servers
If you have multiple back-end servers, a good way to distribute traffic between them when proxying is to use the load balancing function
Replace all content inside the block
VirtualHost as follows, so your config file looks like this:
<VirtualHost *:80> <Proxy balancer://mycluster> BalancerMember http://127.0.0.1:8080 BalancerMember http://127.0.0.1:8081 </Proxy> ProxyPreserveHost On ProxyPass / balancer://mycluster/ ProxyPassReverse / balancer://mycluster/ </VirtualHost>
The configuration is similar to the previous one, but instead of specifying one backend server directly, we used an additional block
Proxy to define multiple servers. Block named
balancer://mycluster (name can be freely changed) and consists of one or more
BalancerMemberthat define the underlying server backend addresses.
ProxyPass and directive
ProxyPassReverse use a load balancing pool named
mycluster instead of a specific server.
If you followed the example in step 2 using
127.0.0.1:8081 for directive
BalancerMemberas written in the block above. If you have your own application servers, use their addresses instead of these.
Restart Apache for the changes to take effect.
sudo systemctl restart apache2
Go to your web browser at http: // your_server_ip, you will see the server backend instead of the default Apache page. If you followed the instructions in Step 2, refresh the page several times should show Hello, peace! and AndreyEx world!That is, the reverse proxy was working and load balancing between both servers.
You now know how to configure Apache as a reverse proxy for one or more of your primary application servers.
mod_proxy can be effectively used to set up a reverse proxy for application servers written in a wide variety of languages and technologies, such as Python and Django or Ruby and Ruby on Rails. It can also be used to balance traffic between multiple back-end servers for sites with a lot of traffic or to provide high availability across multiple servers, or to provide secure SSL support on servers that do not natively support SSL.
mod_proxy_http these are perhaps the most commonly used combinations of modules, there are several others that support different network protocols. We haven’t used them here, but some other popular modules include:
mod_proxy_connectfor SSL tunneling.
mod_proxy_ajpfor AJP (Apache JServ Protocol) like Tomcat based engines.
mod_proxy_wstunnelfor web sockets.
To find out more about
mod_proxy, you can read at Apache official website documentation about