Configs for nginx and Apache with mod_wsgi

(October 9, 2008)

I cleaned up my configuration files for nginx and Apache (running mod_wsgi and Django). It’s pretty straight forward stuff. I use nginx to serve static files and proxy all other requests (like this page) back to Apache.


nginx.conf

user www-data www-data;
worker_processes 4;
pid /var/run/nginx.pid;

error_log /var/log/nginx/error.log;

events {
  worker_connections 1024;
}

http {
  # don't send version in response headers
  server_tokens off;

  include /etc/nginx/mime.types;

  # fallback if none matches
  default_type application/octet-stream;

  # about: http://www.baus.net/on-tcp_cork
  tcp_nopush on;
  sendfile on;

  gzip on;
  gzip_min_length 1000;
  gzip_proxied any;
  gzip_types text/css text/plain application/atom+xml application/x-javascript;
  gzip_vary on;

  server {
    listen 80;
    server_name DOMAIN;
    root /a/DOMAIN/root;

    location / {
      # pass Host header on to the backend
      proxy_set_header Host $host;
      # set X-Forwarded-For header so the backend knows who
      # actually made the request
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      # if there is no matching static file in the root
      # proxy the request to the backend
      if (!-f $request_filename) {
        proxy_pass http://localhost:8000;
      }
    }
  }

  server {
      listen 80;
      server_name media.DOMAIN;
      root /a/DOMAIN/media;
  }
}

apache2.conf

Listen 127.0.0.1:8000

# should be name clients would use reach this host
# and not just the address you happen to bind to
ServerName DOMAIN:80
ServerRoot "/etc/apache2"

User ${APACHE_RUN_USER}
Group ${APACHE_RUN_GROUP}
PidFile ${APACHE_PID_FILE}
LockFile /var/lock/apache2/accept.lock

# nginx doesn't support backend keep-alive yet
KeepAlive Off

# prefork-mpm settings
StartServers          5
MinSpareServers       5
MaxSpareServers       5
MaxClients            5
MaxRequestsPerChild   5000

DefaultType application/octet-stream

ErrorLog /var/log/apache2/error.log
LogLevel warn

# log x-forwarded-for because the request will always
# come from nginx, not the actual user
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog /var/log/apache2/access.log combined

LoadModule wsgi_module /usr/lib/apache2/modules/mod_wsgi.so

# BASELINE is an empty virtual environment that doesn't
# fallback to the global site-packages directory.  Using it
# as the Python home ensures that all WSGI apps run out of
# their own virtualenv, so nothing pollutes anything else.
WSGIPythonHome /a/BASELINE

NameVirtualHost 127.0.0.1:8000

# default virtualhost so that _real_ sites are only
# served when specifically requested
<VirtualHost 127.0.0.1:8000>
    ServerName 127.0.0.1
    DocumentRoot /var/www
</VirtualHost>

<VirtualHost 127.0.0.1:8000>
    ServerName DOMAIN
    DocumentRoot /a/DOMAIN/root
    WSGIScriptAlias / /a/DOMAIN/etc/wsgi.py
</VirtualHost>

wsgi.py

import os
import site

site.addsitedir('/a/DOMAIN/lib/python2.5/site-packages/')
os.environ['DJANGO_SETTINGS_MODULE'] = 'PROJECT.settings'

import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()