Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NGINX Reverse Proxy for upstream Django/Gunicorn Backend

I posted this on the nginx mailing list but haven't heard back from anyone so I thought I'd give it a crack over here on stackoverflow :)

I currently have a Django app hosted up on Amazon EC2. All of my data is served through Gunicorn on port 8000 (a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model ported from Ruby's Unicorn project). I don't have to worry about passing static content (images) to the client because all of that is handled for me by Amazon's S3 service. Django passes the url of the content through Gunicorn to the client via json. The client can then download it.

My Django app is hosted on a t1.micro instance. Here are the specs as provided by Amazon Web Services:

Processor: Up to 2 EC2 compute units (for short periodic bursts). Virtual cores: 1 Memory: 615 MiB Platform: 32-bit and 64-bit

I have 3 Gunicorn workers running alongside my Django app on this instance.

For my Nginx Reverse proxy server, I also use a t1.micro instance. I've set it up and everything is working perfectly fine. Here is my etc/nginx/sites-enabled/default config as follows:

# Gunicorn server
upstream django {
  server         10.0.10.0:8000;
}
# Serve static files and redirect any other request to Gunicorn
server {
  listen       80;
  server_name  23.0.23.23/;
  #root        /var/www/domain.com/;
  #access_log  /var/log/nginx/domain.com.access.log;
  #error_log  /var/log/nginx/domain.com.error.log;

  # Check if a file exists at /var/www/domain/ for the incoming request.
  # If it doesn't proxy to Gunicorn/Django.
  #try_files $uri @django;

  # Setup named location for Django requests and handle proxy details
  location @django {
    proxy_pass         http://django;
    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;
  }
}

This setup is great but it doesn't account for proxy buffering for slow clients. It also doesn't account for caching and it doesn't account for the number of nginx workers I will require. How can I configure the compression? I found resources that state there is something called gzip, does this support json? How can I fine tune my nginx config according to my t1.micro instance specs?

If you we're in my scenario, what settings would you use? Your answers and examples are much appreciated. Thank you :)

like image 400
deadlock Avatar asked Jun 07 '13 19:06

deadlock


1 Answers

Proxy Buffering

Generally proxy buffering is only going to help you if you're generating very big web pages, or sending large files. regardless, it's pretty easy to set up, but you will need to tune the buffer sizes to about the size of your largest pages +20% (Any page that doesnt fit in the buffer gets written to disk), or selectively enable proxy buffering on your largest pages.

docs: http://wiki.nginx.org/HttpProxyModule#proxy_buffering

Caching

I don't know much about your app and how dynamic it's content is, but setting up correct Cache Control/ETAG header generation on your app will be the first thing you'll want to look at. This is what will let Nginx know what is safe to proxy. Also, you may wish to setup multiple cache zones to manage the amount of space your caches take on disk.

proxy_cache one;
proxy_cache_path  /data/nginx/cache/one levels=1:2 max_size=1G keys_zone=one:1000m;

You'll want rules that allow you to bypass the cache (for debugging or programatically)

proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_bypass $http_pragma $http_authorization;

You'll also want to have your app unconditionally serve from cache when your application throws errors:

proxy_cache_use_stale error timeout invalid_header;

docs:

  • http://wiki.nginx.org/HttpProxyModule#proxy_cache
  • http://wiki.nginx.org/HttpProxyModule#proxy_cache_path
  • http://wiki.nginx.org/HttpProxyModule#proxy_cache_use_stale

Gzip

Enabling gzip on your site is always a tradeoff between CPU time and bandwidth. True, you can lower the amount of data sent over the wire if you gzip your content, but if you're running on a T1 Micro, you'll severely limit your capacity for proxying requests due to CPU utilisation. Generally gzip is a much better idea for static content that you can pre-zip and then serve over and over again.

(Yes, gzip supports json, but this is because gzip becomes the wire format, and is transparently unzipped by the client. You should read up on Content-Encoding: gzip)

docs: http://betterexplained.com/articles/how-to-optimize-your-site-with-gzip-compression/

Misc

You'll want to set a few misc settings too:

# Directives turn off 404 error logging.
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
    log_not_found off;
}
like image 163
Thomas Avatar answered Oct 24 '22 20:10

Thomas