Wednesday, June 17, 2009

Using Nginx as a Reverse Proxy

-This how-to is going to assume that you already have a standard LAMP stack running, if not, there are plenty of tutorials and examples on how to get a LAMP stack running.

-We have chosen to go with a standard Apache 2 installation using libapache2_mod_php5 over using Nginx (pronounced ‘Engine X’) with fastCGI. You may be thinking “that is preposterous, why not just use Nginx as your webserver and ditch Apache?” I hate fastCGI, I’ve never had very good luck with it and most importantly I know Apache. Also, when all Apache has to worry about is the dynamic content, in this case PHP, it is quite fast, and has a smaller memory footprint then normal Apache usage.

-Using Nginx as a reverse proxy is great for a few reasons. Firstly it handles static content very well. It is able to handle the requests and serve static content much faster in our tests and this has cut our page load time in about half (using YSlow with a clear cache). The memory footprint of Nginx is very small so this extra speed increase is worth every megabyte, in this case .6 megabytes of our total ram on a 540 megabyte server. Secondly, it allows for quick and easy migration of your Apache services to another server. Through the config files you are able to specify an IP of your server and a port. If your apache server is taking a pounding it wouldn’t be difficult to move it to another server and just change the proxy IP to your now remote server.

-Setting up Nginx is fairly straight forward. I will be showing the commands for an Ubuntu 8.04 installation but they should work for previous versions and other distributions (with a little tweaking).

Install Nginx

sudo apt-get install nginx

the following is essentially the config file we use for /etc/nginx/nginx.conf and is pretty similar to the default config for the installation. The only major thing I changed was adding gzip compression. I have personally set the level to 5 although it is adjustable. The higher you set this value the more CPU intensive it becomes.

user www-data;
worker_processes 2;
error_log /var/log/nginx/error.log;
pid /var/run/;
events {
worker_connections 1024;
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
server_names_hash_bucket_size 64;
sendfile on;
tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
tcp_nodelay on;
gzip on;
gzip_comp_level 5;
gzip_http_version 1.0;
gzip_min_length 0;
gzip_types text/plain text/html text/css image/x-icon
gzip_vary on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

-You are going to want to make sure that the line “include /etc/nginx/conf.d/*.conf;” is included in this config. This is where you will store the default proxy information.

-We will now configure the default proxy. Create the file proxy.conf in the /etc/nginx/conf.d/ folder with the following contents.

proxy_redirect 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;
client_max_body_size 10m;
client_body_buffer_size 128k;
client_header_buffer_size 64k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 16k;
proxy_buffers 32 16k;
proxy_busy_buffers_size 64k;

-The only thing you may want to change is the buffer sizes. We had to increase our proxy_buffer_size and a few others, from the default, to allow for larger cookies that were choking Nginx. With that being said you may want to decrease the buffers a bit, just do some testing. If the buffers are not working for your content Nginx will throw a 50x error.

-Finally, we will configure the various hosts. To save yourself some time, and possible a headache you should always keep your static assets in one folder, while subdividing them by type in containing folders. For example static->images, static->js, static->css. This will greatly simplify your Nginx installation and I’ve found your code.

-Now we will edit (with your favorite CLI editor) /etc/nginx/sites-available/default.

server {
listen 80;
access_log /var/www/;
error_log /var/www/ debug;

#set your default location
location / {

#I had a problem accessing phpmyadmin with an Nginx reverse
#proxy without adding this location
location /phpmyadmin {
deny all;
#set your static folder location without the proxy pass so Nginx
#will server those files. We also set expires max to add an
#expires to have the client cache the files. You will
#have to #set a version on your css and js files to prevent
#the user who has cached files from not receiving new versions.
location /static {
root /var/www/;
expires max;
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/nginx-default;
#If you have a subdomain you need to add a new server if you
#want Nginx to server the static files. Our subdomain only
#serves static files so we have not set up a proxy_pass
server {
listen 80;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/nginx-default;
access_log /var/www/;
error_log /var/www/;
index index.html;
location / {
expires max;
root /var/www/;

-Finally we need to make some quick changes to Apache and we’ll finally have everything running. Edit the file /etc/apache2/ports.conf.

-You’ll want to change the listen line to This will prevent apache from receiving requests from outside, but you should be blocking port 8080 anyways! The port we’ve set is 8080 but whatever you set in the Nginx configs is what you should use.

NameVirtualHost *

-Lastly, if you don’t want all your apache logs to show for who is accessing your files or your application uses IP’s to track sessions you need to install libapache2-mod-rpaf. It is painless just issue the command below.

sudo apt-get install libapache2-mod-rpaf

reload or restart both Apache2 and Nginx.

/etc/init.d/apache2 restart
/etc/init.d/nginx restart

-To see if it is working open a page on your website, if you don’t see any errors that is a good start. You can then check the logs of Apache and Nginx. Your Apache logs should only contain the php requests and your Nginx logs should contain all of your assets. Your Apache logs should also have HTTP 1.0 request when they go through the reverse proxy.

No comments:

Post a Comment