I wrote this article a while ago when my website was using much more resource-hungry software (Drupal). Now I just run Apache allowing it to serve static and dynamic content and everything is fine. I’ve left it here in the hope that some people might find it useful.

The aim of this guide is to set up nginx to serve static content, something which it is good at, and then forward dynamic requests on to Apache to deal with. Maybe you have some legacy Apache config your application needs (e.g. lots of .htaccess files) or perhaps you just can’t get it to work with nginx. It also seemed to provide an improvement in performance once I had tuned the Apache settings so it expected less simultaneous requests (the vast majority of the requests on my site were actually for static content).

This tutorial was written for Ubuntu but I see no reason why it shouldn’t work for Debian. It could probably be adapted to other distributions as well.


I already had Apache installed, however, if you are doing this from scratch you can easily install it like so:

sudo apt-get install apache2

Installing nginx can be done in a similar way:

sudo apt-get install nginx

You will also need mod_rpaf later on in the tutorial and it can be installed like so:

sudo apt-get install libapache2-mod-rpaf


The first thing I did was to change the port nginx listens on. This can be done in the /etc/nginx/nginx.conf file. I simply change the listen 80 line to listen 81. Later on we’ll swap over so nginx is on port 80 and Apache is on port 81. This is just so I could keep things running in the production environment.

I added an upstream server for Apache. In the http block I added this upstream block:

upstream apache {

In the server block I added some settings to expire static content in the future to stop browsers re-requesting it. You could also add additional file types which you want to be static:

location ~ (js|css|gif|jpg|jpeg|png|htm|html|txt|rar|zip|exe|tgz|tar.gz|tar|gz)$ {
    expires 30d;

Following the first location block, I added another to proxy anything else to Apache:

location / {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://apache;
    proxy_redirect default;

The final step is to configure mod_rpaf so that it knows the real client’s IP address. If it is not already enabled, the following command can enable it for you:

sudo a2enmod rpaf

Then to configure it I put this in my /etc/apache2/httpd.conf file:

RPAFenable On
RPAFsethostname On
RPAFheader X-Forwarded-For


Once everything is configured, I suggest rebooting Apache and nginx and testing your new configuration extensively. Remember to use port 81 right now - we will swap 81 and 80 around later.

Finishing up

To finish off I changed Apache to listen on 81 and nginx to listen on 80. Apache’s port can be changed in /etc/apache2/ports.conf. You might also need to change any virtual hosts which you made. nginx’s port can be changed as shown earlier in the tutorial. Once you are sure everything is ready, just reboot them both and your new combination of Apache and nginx will be used for all of your users!

What now?

  • Further testing is a very good idea. There are likely to be several things requiring changes.

  • Tune the Apache and nginx settings to improve performance.

  • If you use virtual hosts, you will need to set up configuration which mirrors Apache’s configuration on nginx so the static content is served correctly.