You might have noticed by now that I really like Nginx. I’ve had an article for using it as a load balancer with SSL termination already, and eventually I’ll get around to setting it up as a web server as well. For this article, I’ll set a situation. You have some PHP application on apache, and have your mod_rewrite wizardry the way you want it, and everything is working -ok-. You’ve heard of this new Nginx thing and want to give it a shot, but don’t want to mess with testing everything on Nginx. So what you can do, is have Nginx listen and serve all your static content (Which it’s really good at), and pass your dynamic content(and whatever else) back to Apache to process. This article will go over the configuration of an Nginx reverse proxy, and modifying apache to work with it.
The first thing you need to do is install it. On Debian, this is quite simply –
Add the following to /etc/apt/sources.list
deb http://nginx.org/packages/debian/ squeeze nginx deb-src http://nginx.org/packages/debian/ squeeze nginx
Now install it:
# aptitude update # aptitude install nginx
Here’s some copy/pasta if you just want the configs:
/etc/nginx/nginx.conf
user nginx; worker_processes 6; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; keepalive_timeout 10; #Compression Settings gzip on; gzip_http_version 1.0; gzip_comp_level 2; gzip_proxied any; gzip_min_length 1100; gzip_buffers 16 8k; gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript; # Some version of IE 6 don't handle compression well on some mime-types, # so just disable for them gzip_disable "MSIE [1-6].(?!.*SV1)"; # Set a vary header so downstream proxies don't send cached gzipped # content to IE6 gzip_vary on; include /etc/nginx/conf.d/*.conf; }
The first bit is pretty self explanatory. We set the user, the number of processes nginx will spawn, where it’s going to store the pid file, and the number of connections each worker will get. Moving down, we have an include(mime.types sets a lot of the MIME types), and set the default MIME type. Moving further down, we set the log format and allow sendfile (which bypasses using read() and write(), you can read about it some here and here.) We set a keepalive_timeout fairly low (it could probably stand be shorter, but 10 seconds should be fine).
The compression settings should be fairly obvious, if you want to read on the specifics on a parameter you can read about them here.
Next, we need to set up the actual proxying:
/etc/nginx/conf.d/proxy.conf
server { listen 80; access_log off; error_log off; location / { proxy_pass http://127.0.0.1:8080; proxy_redirect off; #Proxy Settings 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; proxy_max_temp_file_size 0; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; } location ~* \.(?:ico|css|js|gif|jpe?g|png|bmp|html) { root /var/www; expires max; add_header Pragma public; add_header Cache-Control "public, must-revalidate, proxy-revalidate"; } }
In this section, we do a few things. First we define a server. A server in the context of nginx can be loosely defined as a virtualhost. For instance, if you wanted to have domain1.com and domain2.com, you would end up with two server blocks. In this case, we’re going to specify a server with no server name. If you are going to host multiple domains, you will need to make a .conf for each and set server_name as well as root for each domain unless you don’t want nginx to serve static content for some reason.
The next thing we do is specify two locations. The first specifies anything that matches /, and anything that matches something ending in .ico/css/etc. Nginx matches the most specific location. In this instance, that means /somedir/image.png will match the second rule, as matching “.png” is more specific then matching / (which will match every request to the server). In the ~* \. match, we serve the content with nginx directly – this is because nginx is very good at serving static content and there is no reason to proxy the requests to apache. We add a couple headers (for instance, telling the browser to cache the content as long as possible) and let it go on its way. The other location proxies the request to apache, setting some headers (such as X-Real-IP and X-Forwarded-For), and set the timeouts to the backend (90 seconds) and the buffer sizes. I will refer you (again) to the excellent documentation if you would like to know what all parameters are available, located here.
Finally, we need to change apache to listen on port 8080 instead of 80. The apache configurations vary significantly between distributions, so I won’t point to the specific files, but a grep -Ri should get you what you need.
The configurations we are concerned about are VirtualHost, NameVirtualHost and Listen.
You will need to modify them so they look like this:
NameVirtualHost *:8080 Listen 8080
Once you have done this, check your configurations:
# service nginx configtest # service apache configtest
(note that it is httpd on redhat based systems), assuming everything checks out, restart apache, start nginx and set it to start on boot –
# service apache2 restart # service nginx start # update-rc.d nginx enable
Assuming everything went well, Nginx should now be solving all static content and relaying everything else back to apache. Enjoy your performance boost!
Do you know how to configure nginx to cache static contents when it is running as a reverse proxy?
Excellent stuff Ryuujink.
I’m running nginx on Ubuntu 12.10 with 5 web apps in one box, AND then Apache on OS X (Mac Mini) with a web photo gallery (gallery3) serving a few thousand pictures and videos. I thought about configuring nginx as a reverse proxy for Apache for all the performance benefits it provides. It should be feasible to have Apache handle the gallery app except the actual media (static pictures and videos), which nginx would be ideal to handle, but I’m not sure on the actual details. Do you have any suggestions?
Angelo C
This article describes the basic configuration of a proxy server. You will learn how to pass a request from NGINX to proxied servers over different protocols, modify client request headers that are sent to the proxied server, and configure buffering of responses coming from the proxied servers.