There is a new version of this tutorial available for Ubuntu 16.04 (Xenial Xerus).

How To Set Up nginx As A Reverse Proxy For Apache2 On Ubuntu 12.04

Version 1.0
Author: Falko Timme
Follow me on Twitter

nginx (pronounced "engine x") is a free, open-source, high-performance HTTP server. nginx is known for its stability, rich feature set, simple configuration, and low resource consumption. This tutorial shows how you can set up nginx as a reverse proxy on front of an Apache2 web server on Ubuntu 12.04.

I do not issue any guarantee that this will work for you!

 

1 Preliminary Note

In this tutorial I use the hostname server1.example.com with the IP address 192.168.0.100. These settings might differ for you, so you have to replace them where appropriate.

I'm assuming that you have an existing Apache vhost (I will use example.com in this tutorial) that is listening on port 80 on the IP address 192.168.0.100 that you want to proxy through nginx.

Please note that this tutorial covers http only, not https (SSL).

 

2 Configuring Apache

The first thing we have to do is configure our Apache vhost to listen on localhost (127.0.0.1) on an unused port other than 80 (e.g. 8000). Open /etc/apache2/ports.conf...

vi /etc/apache2/ports.conf

... and modify the NameVirtualHost and Listen lines for port 80 to use port 8000:

# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default
# This is also true if you have upgraded from before 2.2.9-3 (i.e. from
# Debian etch). See /usr/share/doc/apache2.2-common/NEWS.Debian.gz and
# README.Debian.gz

NameVirtualHost *:8000
Listen 8000

<IfModule mod_ssl.c>
    # If you add NameVirtualHost *:443 here, you will also have to change
    # the VirtualHost statement in /etc/apache2/sites-available/default-ssl
    # to <VirtualHost *:443>
    # Server Name Indication for SSL named virtual hosts is currently not
    # supported by MSIE on Windows XP.
Listen 443
</IfModule>

<IfModule mod_gnutls.c>
Listen 443
</IfModule>

Next open the vhost configuration file (e.g. /etc/apache2/sites-available/example.com.vhost)...

vi /etc/apache2/sites-available/example.com.vhost

... and change the <VirtualHost> line to use the IP address 127.0.0.1 and the port 8000:

<VirtualHost 127.0.0.1:8000>
[...]

We will configure nginx as a transparent proxy, i.e., it will pass on the original user's IP address in a field called X-Forwarded-For to the backend Apache. Of course, the backend Apache should log the original user's IP address in their access logs instead of the IP address of nginx (127.0.0.1). There are two ways to achieve this:

1) We can modify the LogFormat line in /etc/apache2/apache2.conf and replace %h with %{X-Forwarded-For}i:

vi /etc/apache2/apache2.conf
[...]
#LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
[...]

2) On Debian/Ubuntu, we can install the Apache module libapache2-mod-rpaf which takes care of logging the correct IP address:

apt-get install libapache2-mod-rpaf

After all these changes, restart Apache:

/etc/init.d/apache2 restart

 

3 Configuring nginx

If nginx isn't already installed, install it as follows:

apt-get install nginx

Create its system startup links and make sure it is started:

update-rc.d nginx defaults
/etc/init.d/nginx restart

It should now be listening on port 80.

Some standard proxy parameters are in the file /etc/nginx/proxy_params:

vi /etc/nginx/proxy_params
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

As we will include that file later on in the proxy part of our nginx vhost for example.com, you can add further proxy directives to that file if you like, e.g. as follows:

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

client_max_body_size 100M;
client_body_buffer_size 1m;
proxy_intercept_errors on;
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 256 16k;
proxy_busy_buffers_size 256k;
proxy_temp_file_write_size 256k;
proxy_max_temp_file_size 0;
proxy_read_timeout 300;

Now create the example.com vhost for nginx - make sure it uses the same document root as the Apache vhost for example.com (e.g. /var/www/example.com/web) so that nginx can deliver static files directly without passing the request to Apache:

vi /etc/nginx/sites-available/example.com.vhost
server {
       listen 80;
       server_name www.example.com example.com;
       root /var/www/example.com/web;
       if ($http_host != "www.example.com") {
                 rewrite ^ http://www.example.com$request_uri permanent;
       }
       index index.php index.html;

       location / {
                proxy_pass http://localhost:8000;
                include /etc/nginx/proxy_params;
       }
}

This is a very simple configuration which would proxy all requests to Apache.

To enable that vhost, we create a symlink to it from the /etc/nginx/sites-enabled/ directory:

cd /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/example.com.vhost example.com.vhost

Reload nginx for the changes to take effect:

/etc/init.d/nginx reload

You can now type www.example.com into your browser, and you should see your web site, but this time delivered through nginx.

As I said before this is a very simple configuration which proxies all requests to Apache. But because nginx is much faster delivering static files (like JavaScript, CSS, images, PDF files, static HTML files, etc.) than Apache, it is a good idea to let nginx serve these files directly. This can be done by adding a new location for these files, e.g. as follows:

server {
       listen 80;
       server_name www.example.com example.com;
       root /var/www/example.com/web;
       if ($http_host != "www.example.com") {
                 rewrite ^ http://www.example.com$request_uri permanent;
       }
       index index.php index.html;

       location / {
                proxy_pass http://localhost:8000;
                include /etc/nginx/proxy_params;
       }
       location ~* \.(js|css|jpg|jpeg|gif|png|svg|ico|pdf|html|htm)$ {
       }
}

Reload nginx:

/etc/init.d/nginx reload

You can even set an Expires HTTP header for these files so that browsers will cache these files (see Make Browsers Cache Static Files On nginx for more details):

server {
       listen 80;
       server_name www.example.com example.com;
       root /var/www/example.com/web;
       if ($http_host != "www.example.com") {
                 rewrite ^ http://www.example.com$request_uri permanent;
       }
       index index.php index.html;

       location / {
                proxy_pass http://localhost:8000;
                include /etc/nginx/proxy_params;
       }
       location ~* \.(js|css|jpg|jpeg|gif|png|svg|ico|pdf|html|htm)$ {
                expires      30d;
       }
}

We can now take this setup one step further by letting nginx serve as many requests as it can fulfill and only pass the remaining requests plus PHP files to Apache:

server {
       listen 80;
       server_name www.example.com example.com;
       root /var/www/example.com/web;
       if ($http_host != "www.example.com") {
                 rewrite ^ http://www.example.com$request_uri permanent;
       }
       index index.php index.html;

       location / {
                try_files $uri @proxy;
       }
       location ~* \.(js|css|jpg|jpeg|gif|png|svg|ico|pdf|html|htm)$ {
                expires      30d;
       }
       location @proxy {
                proxy_pass http://127.0.0.1:8000;
                include /etc/nginx/proxy_params;
       }
       location ~* \.php$ {
                proxy_pass http://127.0.0.1:8000;
                include /etc/nginx/proxy_params;
       }
}

Reload nginx:

/etc/init.d/nginx reload

Of course, you can fine-tune this setup even more, for example by using the nginx proxy_cache (if your application allows it - for example, you must make sure that captchas or shopping carts aren't cached, and that logged-in users always get a fresh copy of the page) or if your application has a full page cache - nginx could access the full page cache directly in such a case (you can find an example in this tutorial: How To Speed Up Drupal 7.7 With Boost And nginx (Debian Squeeze)).

 

 

About The Author

Falko Timme is the owner of nginx WebhostingTimme Hosting (ultra-fast nginx web hosting). He is the lead maintainer of HowtoForge (since 2005) and one of the core developers of ISPConfig (since 2000). He has also contributed to the O'Reilly book "Linux System Administration".

Share this page:

5 Comment(s)