Running nginx in front of Apache
Introduction
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.
Installation
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
Configuration
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 {
server 127.0.0.1:80;
}
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
RPAFproxy_ips 127.0.0.1
RPAFheader X-Forwarded-For
Testing
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.