Using Nginx as a Reverse Proxy to Get the Most Out of Your VPS.

Sponsored Link
Unravel The Music is a small startup; by that I mean we have no money, no financing, and we are owned and operated by two people. Therefore it is important that we get the most out of our server in terms of performance and cost and we have to do this without having to spend hours worrying about the server when we could be improving our design or code.


First off, without good hardware it's not going to matter how well your server is setup because you will be constantly worrying about whether your server is even up or if the datacenter is having another monthly outage. For this problem we recommend Linode. I'm sure there are plenty of other great VPS hosts out there but we have had a lot of luck with Linode and highly recommend them.

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/nginx.pid;
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
	application/x-javascript;
  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;
 server_name  example.com;
 access_log  /var/www/example.com/log/nginx.access.log;
 error_log  /var/www/example.com/log/nginx_error.log debug;

 #set your default location
 location / {
  proxy_pass         http://127.0.0.1:8080/;
 }

 #I had a problem accessing phpmyadmin with an Nginx reverse
 #proxy without adding this location
 location /phpmyadmin {
  proxy_pass         http://127.0.0.1:8080/phpmyadmin;
  allow 1.1.1.1;
  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/example.com/htdocs/;
  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;
 server_name subdomain.example.com;
 error_page 500 502 503 504 /50x.html;
 location = /50x.html {
  root /var/www/nginx-default;
 }
 access_log /var/www/subdomain.example.com/log/nginx.access.log;
 error_log /var/www/subdomain.example.com/log/nginx.error.log;
 index index.html;
 location / {
  expires     max;
  root /var/www/subdomain.example.com/htdocs/;
 }
}

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 127.0.0.1:8080. 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 *
Listen 127.0.0.1:8080

Lastly, if you don't want all your apache logs to show 127.0.0.1 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.

If you need any support just leave a comment and we'll try and help you.

Source

Sponsored Link

Related posts

You may also like...

15 Responses

  1. James D Kirk says:

    Thank you so much for writing up this tutorial. There is a ton of info out there on setting up Nginx with Apache, and having it so cleanly laid out is nice.

    A couple of clarifying questions would be helpful before jumping into the fray:

    1. I’m not seeing any declarations of the types of static files that Nginx would handle in your examples unless it is the “application/octet-stream” or the fact that you are gzipping the static files and that is where they are declared.

    2. You mention it a wise choice to organize static files together in structures like

    “/static-folder/static-file.img-type”

    Is this “required” for Nginx or simply “better”? And either way, does this imply that if Nginx is to serve those files, they have to be located there versus where a CMS might place them (for instance, WordPress placing uploaded images into the wp-content/uploads/ directory)?

    Thanks again. Looking forward to your thoughts on the above.

  2. Drew Town says:

    James,

    Here is the thing, the two are directly related which is why I said it is important to have a static folder.

    location /static {
    root /var/www/example.com/htdocs/;
    expires max;
    }

    These few lines tell Nginx that everything in the static folder it should handle by finding in the /var/www/example.com/htdocs/ folder. So anything coming into such as /static/css/style.css will be handled by Nginx because it is missing the proxy_pass command for this folder. Where as example.com/index.php will be passed to Apache.

    This really works out well because if you only wanted Nginx to server your user uploaded images you would just have the location /wp-content/uploads/ command and apache would be passed everything else. I would definitely recommend having Nginx handle your css and js as we’ve seen great performance increases using this technique.

    Overall it took me about 15-20 minutes to get setup and running.

  3. I am new to ubuntu, i run

    [email protected]:/etc/apt# apt-get install nginx
    Reading package lists… Done
    Building dependency tree… Done
    E: Couldn’t find package nginx
    [email protected]:/etc/apt#

    It says no ngnix, os is Ubuntu 9.04

    How do i get ngnix working ?

  4. drewtown says:

    make sure you run
    sudo apt-get update
    and
    sudo apt-get upgrade

    before you try to install any new packages. Your command is correct and as of Hardy has been in the Universe repository.

  5. Brian says:

    @annie

    you might have to enable the universe section of the official repository.

  6. Omid says:

    Hi, I followed the instruction but at the end when I run

    /etc/init.d/nginx restart
    I get:
    /var/www/subdomain.example.com/log/nginx.access.log” failed (2: No such file or directory)

    What do I miss?
    Thanks

  7. Ro says:

    @Omid

    Make sure the director structure exists.

  8. Philo Kezzar says:

    Hi, I exactly followed your tutorials and thanks a lot for your effort.
    All servers seem to work as intended however, when I check apache2 access log, I see all static files request logs.
    Does it mean apache still handle the static files?
    What should I do?

    ps., memory footprint seems jump from 52MB to 115MB after this setup.

  9. Bob Anchor says:

    Nice tutorial. I’m getting ready to try this out.

  10. Dean Ezra says:

    I find the following configuration lines more useful instead of keeping my status files separate from dynamic in different folders:

    Instead the following lines simply detect the static files file extensions and only proxy pass onto apache for php scripts:

    server { # simple reverse-proxy
    listen 80;
    server_name domain2.com http://www.domain2.com;
    access_log logs/domain2.access.log main;
    # serve static files
    location ~ ^/(images|javascript|js|css|flash|media|static)/ {
    root /var/www/htdocs;
    expires 30d;
    }

    # pass requests for dynamic content to apache
    location / {
    proxy_pass http://127.0.0.1:8080;
    include /etc/nginx/proxy.conf;
    }
    }

    NOTE: I make nginx and apache root and docroots point to the same file dir:

    Of course, both approaches work, just preference really.

    Great tutorial!

  11. Jacqueline says:

    Hi, I’m trying to do a failover for load balancer. I have 2 load balancer, I want to make sure that if one load balancer is down, all my request will be to the other load balancer. This is to ensure that I have no single point of failure. Is it possible to use nginx for this? Thanks.

  12. Arty says:

    I am testing Nginx as a proxy in front of Apache2 and it works great except nginx disables all my rewrites. 301’s do not appear and I have tried about a dozen configurations including proxy_redirect.

    Any idea how to keep my 301’s so that my site has a canonical element?

    My detailed configs are here:
    http://forum.nginx.org/read.php?11,182132

  13. Estiko says:

    I want to ask, how do I configure Nginx as a proxy in webmin?

  14. Mike says:

    hey guys,

    i got some problems with the trailing slash of the url´s.

    eg: link is my-domain.tld/forum/lotto/ this works,
    if users type …/lotto u´ll get this site doesnt exist on this webserver and the link in the browser shows my-domain.tld:8080/forum/lotto

    no errors in nginx logs, only in apache2 logs, and the error says the following:
    [error] [client xx.xx.xx.xx] File does not exist: /etc/apache2/htdocs
    [debug] mod_deflate.c(615): [client xx.xx.xx.xx] Zlib: Compressed 210 to 164 : URL /forum/lotto/

    so how can i fix this problem? maybe you could help me pls?

    thx in advice!

    greetz Mike

  15. Jack chen says:

    Will the proxy reverse work on SSL? How to configure it?

Leave a Reply

Your email address will not be published.