ewams

Reverse HTTP Proxy with NGINX and Apache

Contents: NGINX Reverse Proxy Overview
NGINX can act as a reverse proxy for web applications allowing you to have a diverse and complex backend while presenting a simple unified front end to the Internet. Using NGINX as a reverse proxy for an Apache server farm is fairly straightforward but the Nginx documentation and online examples are difficult to follow and often contradictory. In this how to I will show you the steps required to configure NGiNX as a reverse proxy for an Apache webserver hosting multiple domains. The environment consists of one nginx reverse proxy server named proxy and one Apache web server named web1.

The steps outlined below can cause data loss. Do not run them on a production system without fully understanding the process and testing in a development environment.


These instructions are not meant to be exhaustive and may not be appropriate for your environment. Always check with your hardware and software vendors for the appropriate steps to manage your infrastructure.


Formatting:
Instructions and information are detailed in black font with no decoration.
Code and shell text are in black font, gray background, and a dashed border.
Input is green.
Literal keys are enclosed in brackets such as [enter], [shift], and [ctrl+c].
Warnings are in red font.




Create Nginx Reverse Proxy for Apache
  1. Log in to the proxy server and launch a shell then change to root.
    user@proxy~$: su -[enter]
    Password:
    root@proxy~$:

  2. Verify software versions.
    root@proxy:~# uname -a[enter]
    Linux proxy 3.2.0-4-amd64 #1 SMP Debian 3.2.57-3+deb7u2 x86_64 GNU/Linux
    root@proxy:~# nginx -v[enter]
    nginx version: nginx/1.2.1

  3. Create a configuration file in /etc/nginx/conf.d/ to keep the reverse proxy information.
    root@proxy:~# vi /etc/nginx/conf.d/default.conf[enter]

  4. Create a config for a single domain.
    server {
            listen 10.1.1.180;
            server_name *.ewams.net;

            location / {
                    proxy_pass http://10.1.1.181;
                    proxy_redirect off;
                    proxy_buffering off;
                    proxy_set_header        Host        $host;
                    proxy_set_header        X-Real-IP        $remote_addr;
                    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
            }
    }
    The first line creates the initial server block.
    The listen line defines what IP address to listen and serve on.
    The server_name is the domain that NGINX will match against. In this example I want Nginx to catch everything for ewams.net, this would include www.ewams.net, email.ewams.net, etc.
    Location directive here with "/" will match any URL on the domain specified. You can be more specific but I have chosen a catch all, so even if someone goes to ewams.net/bob/something it will still match.
    The proxy_pass directive tells nginx where to proxy the connection to.
    The proxy_redirect command sets the "Location:" information in the header. I do not want to change this because I want users that go to ewams.net/someurl to still see ewams.net/someurl so I set it to off.
    The proxy_buffering command allows for NGiNX to perform caching for your platform, I am leaving this disabled as I only want a reverse proxy.
    The proxy_set_header section configures items for the http headers. The first one, host, defines the host that the user is trying to reach, such as ewams.net. The Nginx documentation recommends using $host over $http_host because sometimes the $http_host variable may not be set and in that case the headers will not include the host information. The X-Real-IP defines the actual IP address of the user. The X-Forward-For lets Apache know through the http headers that the user's connection is being proxied.

    With this configuration it is important to note that all data to the website will pass through the proxy server. Even after the initial connection all data to the server and to the user will pass through the Nginx reverse proxy. This means that if you have 300 requests a second coming in, the Nginx server must broker both the 300 user requests and the connections to the Apache server.

  5. Add a configuration section for a second website to the same file.
    server {
            listen 10.1.1.180;
            server_name *.eric.com;

            location / {
                    proxy_pass http://10.1.1.181;
                    proxy_redirect off;
                    proxy_buffering off;
                    proxy_set_header        Host        $host;
                    proxy_set_header        X-Real-IP        $remote_addr;
                    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
            }
    }
    Everything is the same and works as it does in the previous step except I have told NGINX to also listen for everything on the eric.com domain. I am passing both requests for ewams.net and eric.com to the same web server.

  6. Save the configuration file.
    [esc][esc][SHIFT+ZZ]
    root@proxy:~#

  7. Restart NGiNX.
    root@proxy:~# service nginx restart[enter]
    Restarting nginx: nginx.

  8. Log in to the web server and launch a shell then change to root.
    user@web1~$: su -[enter]
    Password:
    root@web1~$:

  9. Verify software versions.
    root@web1:~# apache2 -v[enter]
    Server version: Apache/2.2.22 (Debian)
    Server built: Jun 16 2014 03:51:14

  10. Modify Apache to configure the correct IP addresses for logging. Find the part in the apache2.conf file looks like this:
    LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
    LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %O" common

  11. Change each "%h" to "%{X-Forwarded-For}i". The configuration should now look like this:
    LogFormat "%v:%p %{X-Forwarded-For}i %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
    LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %O" common
    Remember the X-Forwarded-For directive we defined in the nginX configuration? That data is used here to make the logs accurate. If this step is not done all of the Apache logs will say that every request came from the proxy server.

  12. Save the configuration file.
    [esc][esc][SHIFT+ZZ]
    root@proxy:~#

  13. Restart Apache.
    root@web1:~# service apache2 restart[enter]
    [....] Restarting web server: apache2
    ok
    root@web1:~#

  14. Go to your website URL.



Conclusion
The steps above create a reverse proxy nginx server to an Apache HTTP web server. You can repeat step 4 to add multiple domains, I am currently using this configuration for seven websites. There are other configurations that can be achieved, such as multiple front end nginx proxy servers, or multiple back end web servers, or multiple front and back end servers which give even more flexibility.

References
P.S. You may have noticed I typed Nginx several different ways throughout this article. It is a jab at nginx because they are not consistent in their documentation or even in their naming scheme for NGINX!

*disclaimer* This document is my own and does not represent anything from any other entity. I will not be held liable for anything bad that comes of it.

Written by Eric Wamsley
Posted: July 19th, 2014 6:47pm
Topic: Nginx, Apache, reverse proxy
Tags: Nginx, Apache, reverse_proxy, http, load_balancer,


 ©Eric Wamsley - ewams.net