Step By Step Guide To Configure Apache Reverse Proxy

S

You should know that the regular proxies used normally and reverse proxy work on very different concept.

Before we go ahead with learning how to setup an Apache Reverse proxy, let us know what a reverse proxy is and why is it used.

In simple terms, a reverse proxy is a type of proxy server which is used to retrieve information from one or more servers on behalf of a client. So basically it is a mediator between you and the target server.

There are several purposes for using it, of which below are few of them:

  1. It shields application frameworks which basically has weaker http functionality.
  2. It can hide the existence of the main server and also prevent DoS and DDoS attacks.
  3. It can act as a load balancer by distributing the load on several servers in turn improving the load time.
  4. It can optimize the actual content to speed up the response time.
  5. It can add HTTP authentication to the server which has less authentication or security.

Now that we know some basics about reverse proxy and what it can do, let us proceed with setting up an Apache Reverse proxy server.

Step 1: Setting up a Backend server

The purpose of a reverse proxy is that of protecting an application server, However, you should be well versed with Apache to understand the purpose of the commands. For setting up backend, we will be using socat which is a short term for Socket Cat.

$> socat -vv TCP-LISTEN:8000,bind=127.0.0.1,crlf,reuseaddr,fork SYSTEM:”echo

HTTP/1.0 200;\
echo Content-Type\: text/plain; echo; echo ‘Server response, port 8000.'”

Now, using the below command let us instruct or direct Socat to bind the receiver to port 8000. Once done, the additional parameters will make sure that the receiver is permanently connected.

$> curl -v http://localhost:8000/
* Hostname was NOT found in DNS cache
*  Trying 127.0.0.1…
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:8000
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200
< Content-Type: text/plain
<
Server response, port 8000
* Closing connection 0

Using the above command, the backend setup is completed in a simpler way, but this can be modified as per your requirements.

Step 2: Installing Proxy module

There are a lot of modules used in Apache to make it a reverse proxy, however, mod_proxy is one such module which will setup Apache in a way it has to.

In this case, two modules are used to setup Apache as a reverse proxy server, mod_proxy and mod_proxy_http  which is required for http requests. The term proxying actually means receiving a request and pushing it to another server.

In this case, we will have to define the backend server and then accept requests from clients.

It should not be confused that normal proxies which are used in day to day life can also be used on Apache, the purpose for those proxies are completely different from the one we are setting up now. Hence a directive that turns off the request from the default “ on “ mode has to be used.

ProxyRequests Off

Step 3: ProxyPass Directive

Out of the many ways used to instruct Apache to redirect the request to the backend application, ProxyPass directive is the most common and widely used module/directive.

ProxyPass          /service http://localhost:8000/service
ProxyPassReverse   /service http://localhost:8000/service<Proxy http://localhost:8000/service>Require all grantedOptions None</Proxy>

The directive defines a service path and specifies how it is to be related to the backend, if the service runs on localhost or port 8000, the path will be the same as the origin.

Redirect responses from the backend are absolutely qualified in http-compliant type like https://backend.example.com/service1. The reverse proxy has to rewrite the backend’s location header, backend.example.com, substituting it with its own name and so mapping it back to its own namespace.

ProxyPassReverse, on the other hand with such a unique name, solely encompasses a straightforward search and replace feature touching the location headers. As already seen within the ProxyPass directive, proxying is again symmetric: the path here is rewritten 1:1.

Step 4: Exceptions in Proxying

From the previous step of using ProxyPass directive, it is certainly evident that all the requests are passed from /service to the backend. But what if you are not happy with forwarding all the request and say deny few paths to be away from getting exposed to internet? Exceptions can be used in these cases.

Let us take an example of a path /service/index to be prevented from being exposed to internet, ProxyPass directive can be defined in a way to deny the path being forwarded using an exclamation mark, but it is very important to define the rule before configuring or defining the actual proxy setup commands as below.

ProxyPass          /service/index !
ProxyPass          /service http://localhost:8000/service
ProxyPassReverse   /service http://localhost:8000/service

It is often noticed that the entire address is forwarded to the backend server which is actually quite dangerous making yourself vulnerable to a pool of IP addresses attacking your server in any way possible. It is as above that we should define paths or maybe only define paths that are practically being used.

ProxyTimeout Directive: Along with exceptions comes another important directive that is ProxyTimeout directive. This is considered to be important as there are some addresses which are not essential for execution and often lead to timeout, but one disadvantage of the timeout directive is while the client is processing a request and we tend to believe that the request will be processed quickly but the server decides to take its own time,

ProxyTimeout            60

Well in these cases, a reverse proxy easily interrupts a process with the backend. However, it should be noted that the ProxyTimeout directive is included in finding the duration of processing time between the IP packets, and not the time on services at backend.

ProxyErrorOverride: Error messages are one reason which shows backend systems are not provided with the safety that is really necessary. With having detailed error message is the capability to find the root cause of the issue in simple steps rather debugging the entire command. This is in the interest of not letting the connection get exposed to internet, as reverse proxy without authentication is as vulnerable as using a normal internet connection where attackers will be found lurking the client to find ways to bypass the connection.

ProxyErrorOverride      On

ProxyErrorOverride enables hiding the errors sent by the backend application be replaced by Error messages from reverse proxy making it difficult for any intruder to figure out where the problem lies. So the main purpose of this directive is to directly take part in HTTP response to replace any error code which is above or equal to 400. Anything below 400 is considerable and does not affect the directive.

Step 5:  Mod-Rewrite

Along with the ProxyPass directive, Rewrite plays an important role in enabling or modifying features for reverse proxy, also has a very flexible configuration.

Mod-Rewrite is mainly used as it defines its own rewrite engine to alter or change http requests. The rewrite engine can run both on the server as well as virtual host, what’s important for us to know is how it runs on a server.

LoadModule              rewrite_module modules/mod_rewrite.so

RewriteEngine           On
RewriteOptions          InheritDownBefore

RewriteRule           ^/$ %{REQUEST_SCHEME}://%{HTTP_HOST}/index.html  [redirect,last]

Once the rewrite engine is initiated on the server level, the rules are redirected to the rewrite engines, so that the rules are executed before it goes further. Once the actual rule is executed, the client is instructed to send a request to a path, let us take an example of /index.html i.e one request without a path and one request for “/”.

The above being a redirect, the most important part here is for the redirect to indicate the pattern of request, http, https or hostname. As this is implemented at a server level, relative paths won’t work as well. As we do not want to expose the hostname to internet, it is preferred to take the hostname from client request.

The brackets at the end of the rule indicate that a redirect is necessary to instruct the rewrite engine to end the process[last].

Further, the rule can be altered and presented as the one below for which a different redirect is found.

$> curl -v http://localhost/

* Hostname was NOT found in DNS cache
*  Trying 127.0.0.1…
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost
> Accept: */*
>
< HTTP/1.1 302 Found
< Date: Thu, 10 Dec 2015 05:24:42 GMT
* Server Apache is not blacklisted
< Server: Apache
< Location: http://localhost/index.html
< Content-Length: 211
< Content-Type: text/html; charset=iso-8859-1
<
<!DOCTYPE HTML PUBLIC “-//IETF//DTD HTML 2.0//EN”>
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href=”http://localhost/index.html”>here</a>.</p>
</body></html>
* Connection #0 to host localhost left intact

With the above code, a 302 error is found returned, similarly lot more error codes such as 301, 303, 307 and 308 are also found, but the most important aspect here is the location header. Which instructs the client to send a request for a fully qualified URL address with the same pattern mentioned in above set of rules.

In the set of rules in response, you can find a redirect linked with an HTML text, this is a very rare case added for the user to click for a manual redirect in case the browsers do not initiate an automatic redirect, however, this is to be noted in rare cases where browsers do not allow popups or auto-redirects.

The main question here is why the rewrite engine is used only on server level and not on virtual host, The reason is all the rules that execute on port 80 has to also execute on secure port 443. Thus the below rule is used to redirect requests from port 80 to port 443 enabling encryption.

<VirtualHost 127.0.0.1:80>

RewriteEngine        On

RewriteRule        ^/(.*)$ https://%{HTTP_HOST}/$1    [redirect,last]

</VirtualHost>

The pattern shown above is very clear, however, includes a parenthesis ($1) which shows that all the forwarding requests are using the same URL on port 80 and port 443.

Step 6: Mod-Rewrite – [ proxy ]

The above directive of ModRewrite is completely different from what is explained in this subtopi. Here Mod-Rewrite is used to setup a reverse proxy,

<VirtualHost 127.0.0.1:443>

RewriteEngine    On
RewriteRule        ^/service1/(.*)    http://localhost:8000/service1/$1 [proxy,last] ProxyPassReverse    /   http://localhost:8000/
<Proxy http://localhost:8000/service1>
Require all granted
Options None
</Proxy>

The instruction pursues an example like the variation utilizing ProxyPass. Here, in any case the last section of the way must be blocked by using a bracket and again demonstrated by “$1” like the above example commands. ProxyPassReverse and the ProxyStanza stay the same while setting up ProxyPass.

There is no genuine preferred standpoint over ProxyPass sentence structure in this example. Referencing paths by utilizing $1, $2, provides flexibility in executing commands. However, it is to be made sure that RewriteRule and ProxyPass don’t clash by calling the same request and affecting each other.

Nonetheless, it might now be that we need to utilize a single proxy to join different backends or to distribute the load over several servers. This is when load balancer comes to play.

Step 7: Load Balancer

Let us start the process by loading the balancer module, However, besides the load balancing module, it is important to have a module that distributes requests to different servers as well. The best and the oldest route followed will be the lbmethod_byrequests_module which has the ability to distribute requests evenly over all the servers in a sequence of once from left and once from right.

LoadModule        proxy_balancer_module           modules/mod_proxy_balancer.so
LoadModule        lbmethod_byrequests_module      modules/mod_lbmethod_byrequests.so
LoadModule        slotmem_shm_module              modules/mod_slotmem_shm.so

There are a lot of algorithms available for load balancing. Here are the four popular algorithms commonly used, this is only for reference purposes as we will be using the first method.

  • mod_lbmethod_byrequests (counts requests)
  • mod_lbmethod_bytraffic (sizes of requests and responses)
  • mod_lbmethod_bybusyness (Load balancing based on active threads)
  • mod_lbmethod_heartbeat .

We would also need a module to manage segments of the memory used on the server, this will be managed by a direct/command – mod_slotmem_shm.so

Once these directives are setup, we can proceed to setup the load balancer using the RewriteRule with the below command:

RewriteRule         ^/service1/(.*)  balancer://backend/service/$1   [proxy,last] ProxyPassReverse    /  balancer://backend/
<Proxy balancer://backend>
BalancerMember http://localhost:8000 route=backend-port-8000
BalancerMember http://localhost:8001 route=backend-port-8001
Require all granted
Options None
</Proxy>

With the above command, we will be defining 2 backends, one with port 8000 and another port with 8001. The port 8001 will be defined using the Socat for a quicker setup.

Step 8: RewriteMap for proxy setup

Rewrite Maps are the most important concept used in every request sent for the backend by the client.

Under RewriteMaps, the following maps are available:

txt : A key value in a text file is searched for here.

rnd : Several values can be specified for each key with this map.

dbm : This variation is similar to txt variation, but provides a good speed as a binary hash table is in use.

int : An abbreviation for internal function and refers to a function from the following list: toupper, tolower, escape and unescape.

prg : External scripts are invoked in this variation. The script is run along with the server and each time the RewriteMap is accessed a new input via STDIN is received.

dbd und fastdbd : The response value can be searched in a database request.

Seeing the above scripts, it is evident that RewriteMaps are very flexible and can be used in various situations, however, it is of utmost importance that a request from a client goes to the same backend and the requests are not confused while sent back. This can be done using a Cookie, but it is important not to risk the server, hence ModSecurity is used. The use of ModSecurity is simple as it calculates the hash value of the client IP address and then converts it into a hexadecimal string using ModSecurity as below:

SecRule REMOTE_ADDR    “^(.)” \
“phase:1,id:50001,capture,nolog,t:sha1,t:hexEncode,setenv:IPHashChar=%{TX.1}”

Here HexEncode is used to convert the binary hash value into a readable hexadecimal or sha1 readable format and then apply the regular expression to this value.

If you are not sure of whether this will really work, you can find an alternative by changing the variable IPHashChar to %{IPHashChar}e which is elaborate in the below command.

RewriteMap hashchar2backend “txt:/apache/conf/hashchar2backend.txt”
RewriteCond     “%{ENV:IPHashChar}”     ^(.)
RewriteRule     ^/service1/(.*) \
http://${hashchar2backend:%1|localhost:8000}/service1/$1 [proxy,last] <Proxy http://localhost:8000/service1>
Require all granted
Options None
</Proxy>
<Proxy http://localhost:8001/service1>Require all granted
Options None
</Proxy>

We introduce the map by utilizing the RewriteMap command. we have a tendency to assign it a name, outline its kind and also the path to the file. RewriteMap is invoked in a RewriteRule. Before we actually access the map, we have to enable or execute a rewrite condition. this can be done utilizing the RewriteCond directive.

Thereby referencing the IPHashChar setting variable and verifying the primary bit of the variable. As one bit is enclosed within the variation, the command can be executed. Apparently, we have to use the S1 to communicate with the rewrite conditions captured in parenthesis.

The RewriteRule variable isn’t affected with this and continues to be forwarded via $1. once the $1 comes the standard value is separated by a pipe character. In case of failure in accessing the map, then communication with localhost takes place over port 8000 by default.

With the RewriteMap a better performance is provided by the hash file compared to the text file added in the above code. However, as the purpose can also be achieved with the text file, no changes need to be made.

Step 9: Forwarding Information to the backend servers

Although the purpose and the importance of all the aspects are studied in the above topics, it should be noted that reverse proxy completely shields the application from direct client access, which indicates that the application is completely isolated from client details or the type of reverse proxy connection being used. To avoid this, ProxyModule sets few HTTP requests to allow the application to know the nature of the reverse proxy.

  • X-Forwarded-For : The IP address of the reverse proxy
  • X-Forwarded-Host : The origin HTTP host header in the client request
  • X-Forwarded-Server : Name of the reverse proxy server.

Note : When multiple reverse proxies are used, the IP addresses and the server names are separated by a comma. This is the best idea to identify the request and also gather more information.

As reverse proxy is used to authenticate, even if not setup or defined, the value remains empty. Altogether, once the server, encryption and the reverse proxy is set up, the entire block looks as below:

GET /service1/index.html HTTP/1.1
Host: localhost
User-Agent: curl/7.35.0
Accept: */*
X-RP-UNIQUE-ID: VmpSwH8AAQEAAG@hXBcAAAAC
X-RP-REMOTE-USER: (null)
X-RP-SSL-PROTOCOL: TLSv1.2
X-RP-SSL-CIPHER: ECDHE-RSA-AES256-GCM-SHA384
X-Forwarded-For: 127.0.0.1
X-Forwarded-Host: localhost
X-Forwarded-Server: localhost
Connection: close

Step 10: Apache Restart

Once all the directives are successfully setup, along with the ProxyModule, it is recommended to restart apache to apply all the changes and values.

Conclusion

Now that all the setup information is explained precisely in the above steps, it is recommended to setup all the directives if you have thorough knowledge about the same and on stable servers. It should also be noted that there are various methods of setting up Reverse proxy on Apache of which the above mentioned is a simplest one, but if you are a tech geek and want to explore all the ways to setup a reverse proxy, you can always try it.

About the author

Rachael Chapman

A Complete Gamer and a Tech Geek . Brings out all her thoughts and Love in Writting Techie Blogs.

Browse by Category

JOIN OUR NEWSLETTER

Type e-mail address in the box below to receive latest news.

FOLLOW US