Here are my notes on setting up nginx as a reverse proxy with Apache, mod_python, and Django on Ubuntu Intrepid. Nginx is used to serve my static media files while all other requests are passed on to the Apache/mod_python/Django web server.

I realize mod_wsgi has become the preferred way to deploy Django, but I'm a little behind the times and am still using mod_python. I hope to switch to mod_wsgi soon.

I have been using Amazon's CloudFront service for delivering my static media files. As far as I can tell, it has worked well. My main reason for switching to nginx is so I can skip the extra step of uploading to Amazon. Regarding my concern about the memory footprint of nginx, it looks like it is using around 5mb with my two process configuration.

My configuration parameters are shown below. I'm running two sites, SaltyCrane and HandsOnCards on a Slicehost 256mb plan.

Description HandsOnCards SaltyCrane Redirection http://www.handsoncards.com is redirected to http://handsoncards.com http://saltycrane.com is redirected to http://www.saltycrane.com Static media filesystem path /srv/HandsOnCards/handsoncards/static/ /srv/SaltyCrane/iwiwdsmi/media/ Static media web path /site_media/ /site_media/ Django settings.py file location /srv/HandsOnCards/handsoncards/settings.py /srv/SaltyCrane/iwiwdsmi/settings.py Additional Python packages path /srv/python-packages /srv/python-packages

Install nginx

Some recommend installing nginx from source, but I took the easier route and used Ubuntu's package manager.

sudo apt-get install nginx

Nginx configuration

Edit /etc/nginx/nginx.conf :

user www-data 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 ; sendfile on ; tcp_nopush on ; keepalive_timeout 3 ; tcp_nodelay off ; gzip on ; gzip_comp_level 2 ; gzip_proxied any ; gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript ; server { listen 80 ; server_name www.handsoncards.com ; rewrite ^/(.*) http://handsoncards.com/ $1 permanent ; } server { listen 80 ; server_name handsoncards.com ; access_log /var/log/nginx/handsoncards.com.access.log ; error_log /var/log/nginx/handsoncards.com.error.log ; location / { proxy_pass http://127.0.0.1:8080/ ; include /etc/nginx/proxy.conf ; } location /site_media/ { alias /srv/HandsOnCards/handsoncards/static/ ; expires 24h ; } } server { listen 80 ; server_name saltycrane.com ; rewrite ^/(.*) http://www.saltycrane.com/ $1 permanent ; } server { listen 80 ; server_name www.saltycrane.com ; access_log /var/log/nginx/saltycrane.com.access.log ; error_log /var/log/nginx/saltycrane.com.error.log ; location / { proxy_pass http://127.0.0.1:8080/ ; include /etc/nginx/proxy.conf ; } location /site_media/ { alias /srv/SaltyCrane/iwidsmi/media/ ; expires 24h ; } } }

Edit /etc/nginx/proxy.conf :

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 ; proxy_connect_timeout 90 ; proxy_send_timeout 90 ; proxy_read_timeout 90 ; proxy_buffers 32 4k ;

Restart Nginx

sudo /etc/init.d/nginx restart

Install Apache

I already had Apache and mod_python installed, but in case you don't:

apt-get install apache2 apache2-mpm-prefork apt-get install libapache2-mod-python

Apache Configuration

Edit /etc/apache2/httpd.conf :

MaxClients 2 MaxRequestsPerChild 350 KeepAlive Off NameVirtualHost 127.0.0.1:8080 Listen 8080 <VirtualHost 127.0.0.1:8080> ServerName www.saltycrane.com <Location "/"> SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE iwiwdsmi.settings PythonPath "['/srv/SaltyCrane', '/srv/python-packages'] + sys.path" PythonDebug Off </Location> </VirtualHost> <VirtualHost 127.0.0.1:8080> ServerName handsoncards.com <Location "/"> SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE handsoncards.settings PythonPath "['/srv/HandsOnCards', '/srv/python-packages'] + sys.path" PythonDebug Off </Location> </VirtualHost>

Edit /etc/apache2/ports.conf and comment out the following two lines:

#NameVirtualHost *:80 #Listen 80

Restart Apache

sudo /etc/init.d/apache2 restart

Add Django's reverse proxy middleware

Edit your settings.py file to include django.middleware.http.SetRemoteAddrFromForwardedFor in MIDDLEWARE_CLASSES . This allows your Django application to use the real IP address of the client instead of 127.0.0.1 from your nginx proxy. It sets Django's request.META['REMOTE_ADDR'] to be request.META['HTTP_X_FORWARDED_FOR'] which we set above in nginx's proxy.conf . For more information, see the Middleware reference in the Django documentation.

MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.middleware.http.SetRemoteAddrFromForwardedFor', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', )

References

http://bart.whahay.net/blog/2009/04/06/setting-up-nginx-django.html (my main reference)

http://articles.slicehost.com/2009/3/5/ubuntu-intrepid-nginx-configuration (general nginx configuration)

http://articles.slicehost.com/2009/3/6/ubuntu-intrepid-nginx-virtual-hosts-1 (nginx virtual hosts configuration)

http://forum.slicehost.com/comments.php?DiscussionID=2964 (explains the difference between root and alias in nginx.conf.)

Errors