How to use Apache as a reverse proxy with mod_proxy on Debian 8

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.

Prerequisites

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_proxy_balancer and 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.

nano ~/backend1.py

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 ( Hello world!). @app.route("https://andreyex.ru/") над 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.

nano ~/backend2.py

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 /dev/null

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

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:

curl http://127.0.0.1:8080/

This will output Hello World! in the terminal. Checking the second server:

curl http://127.0.0.1:8081/

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.

Note

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:

/etc/apache2/sites-available/000-default.conf

<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:

  • ProxyPreserveHost makes Apache pass the original Host header to the internal server. This is useful as it makes the backend server a conscious address used to access the application.
  • ProxyPass main 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. http://your_backend_server/example
  • ProxyPassReverse must 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 mod_proxy

Replace all content inside the block VirtualHost as follows, so your config file looks like this:

/etc/apache2/sites-available/000-default.conf

<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:8080 and 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.

Output

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.

While mod_proxy from 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_ftp for FTP.
  • mod_proxy_connect for SSL tunneling.
  • mod_proxy_ajp for AJP (Apache JServ Protocol) like Tomcat based engines.
  • mod_proxy_wstunnel for web sockets.

To find out more about mod_proxy, you can read at Apache official website documentation about mod_proxy

Sidebar