Setting up Nginx in front of Apache2 on Ubuntu Server

I love my little Linode (shameless referral link), running several sites on the smallest instance available which gives just 512Mb of memory. With the popularity of HL Twitter and Plex Export, I pretty often max out the available memory and Apache starts dropping requests. So I recently set about looking at the best way to reduce my memory footprint and settled on dropping Nginx in front of Apache. This guide explains how and why.

Apache is a memory hog, with each request loading up a full instance including mod_php et al. Nginx (pronounced Engine-X) on the other hand is designed to be lightweight and fast, very fast. It excels at serving static content, but its features don’t end there. In the past I tried using Nginx and routing dynamic requests to PHP with FPM, but this ended up being more trouble than it was worth.

This time I would serve all requests for existing files via Nginx, anything else would be passed on to Apache running behind the scenes. As such, Nginx would receive all requests on port 80, while Apache would be relegated to 8080.

This guide serves as a reference for myself, but I figured others may find it useful. If you find anything incorrect or have a better idea, please leave a comment! At the time of writing, the following softwares were used:

  • Ubuntu Server 11.04
  • Nginx 1.0.5
  • Apache2 2.2.19
  • PHP 5.3.5

Begin by setting up your server if you haven’t already, with the necessary directories. We’ll be using SSH so make sure you can login and have root access.

ssh user@host
mkdir -p /srv/www/mysite.com/{logs,public_html}

Install Nginx and tell it to listen on port 80:

sudo apt-get install nginx

Create a new site definition in Nginx. We tell Nginx to try loading any files or directories that have been requested, if that fails route the request through index.php. Any requests for a php file are routed through to Apache. This is a very simple set-up, and can be tweaked as needed.

sudo vi /etc/nginx/sites-available/mysite.com
server {
        listen 80;
        access_log /srv/www/hybridlogic/logs/nginx.access.log;
        error_log /srv/www/hybridlogic/logs/nginx.error.log;
        root /srv/www/hybridlogic/public_html;
        index index.php index.html;

        server_name hybridlogic.dev;

        location \ {
                try_files $uri $uri/ index.php/$uri;
        }

        location ~* ^.*\.php$ {
                if (!-f $request_filename) {
                        return 404;
                }
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $host;
                proxy_pass http://127.0.0.1:8080;
        }

        location ~ /\.(ht|git) {
                deny all;
        }
}
sudo ln -s /etc/nginx/sites-available/mysite.com /etc/nginx/sites-enabled/mysite.com
sudo nginx -t
sudo /etc/init.d/nginx restart

Nginx should now be up and running. If you visit mysite.com/static-file.html it should load without ever having touched Apache! Now it’s time to make Apache listen for those dynamic requests.

sudo apt-get install apache2
sudo vi /etc/apache2/sites-available/mysite.com
<VirtualHost *:8080>
        ServerName mysite.com
        DocumentRoot /srv/www/mysite.com/public_html/
        CustomLog /srv/www/mysite.com/logs/apache.access.log common
        ErrorLog /srv/www/mysite.com/logs/apache.error.log
</VirtualHost>
sudo a2ensite mysite.com
sudo /etc/init.d/apache2 reload
sudo /etc/init.d/apache2 restart

We’re just missing PHP and MySQL now.

sudo apt-get install mysql-server php5 php5-mysql php5-suhosin
sudo /etc/init.d/apache2 restart

And that’s it. You should now have a fully functional LEAMP stack. To test if files are being served correctly, use the Web Inspector tool provided in Chrome/Safari or Firebug for Firefox and inspect the network requests. Nginx should appear as the Server in the Response Headers, with an X-Powered-By header present for dynamic requests served by Apache.