Posts Tagged ‘passenger’

Nginx and Django

September 14th, 2009

In a previous guide I showed how to use Passenger (aka mod_rails) to work with Python (WSGI) scripts. While this proved effective for simple wsgi applications, a framework such as Django required a bit more love. This guide assume you already have everything installed from the previous guide, and that Python has already been configured with Django and other modules.

Aside from having the usual setup, you will need the original Django source files. One way of going about this is downloading the latest source from the Django Project. The next couple of steps assume you have nginx installed at the /usr/local/nginx/ location, and already have a src folder under your home folder.

# cd ~/src
# wget http://www.djangoproject.com/download/
# tar zxvf Django-1.1.tar.gz
# cd Django-1.1
# mv ./django /usr/local/nginx/html

I should note, my /html/ folder isn’t publicly accessible because all my sites are subfolders under that location. I use it primarily to store resources for the folders beneath it. You can change where you save the source, just remember where you put it and that the webserver has access to it.

Open up your nginx configuration where you have already setup a passenger app from the previous guide. Should look something like this.

server {
	server_name project.domain.com;
	root /usr/local/nginx/html/project.domain.com/public/;
	passenger_enabled on;
}

The first thing you have to do to set this up for Django (at the very least), is to modify the server block above to something more like this:

server {
	server_name project.domain.com;
 
	location / {
		root /usr/local/nginx/html/project.domain.com/public/;
		passenger_enabled on;
	}
 
	location /media {
		alias /usr/local/nginx/html/django/contrib/admin/media;
	}
}

Now you have either create or move your django application into the site folder. For example, if your site is defined as /usr/local/nginx/html/project.domain.com like above, and your django application is called mytest , you will end up having it located in /usr/local/nginx/html/project.domain.com/mytest. In the end you should have a folder structure similar to this (based off the Django tutorials).

Directory Structure

Now open up the passenger_wsgi.py from the previous guide which may look something like this:

import sys
import os
 
def application(environ, start_response):
	start_response("200 OK", [])
	ret = ["%s: %s\n" % (key, value)
		for key, value in environ.iteritems()]
	return ret

We’re going to turn this into a WSGI initializer for the Django application like so:

import os, sys
 
#automatically finds application's current path
nginx_configuration= os.path.dirname(__file__)
project = os.path.dirname(nginx_configuration)
workspace = os.path.dirname(project)
sys.path.append(workspace) 
 
os.environ['DJANGO_SETTINGS_MODULE'] = 'testapp.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

After saving, should restart the nginx server, then load up the site in a browser. If this is a new Django application you’ll be greeted with a “Welcome to Django” page, otherwise the application you had already created.

Static content can be access by creating additional Aliases in Nginx, or by using django.views.static.serve method in your applications url settings.

Using Python with Nginx via Passenger

September 14th, 2009

Since Nginx 0.6.* I been looking for an effective way to run Python (WSGI) applications thru the Nginx Webserver. A couple of options were available at the time:

Update 1/31/2011: There is now an article showing how to deploy Python (namely with Circuits.web) via Nginx + uWSGI.
Deploying circuits.web with Nginx/uwsgi.

Update 9/29/2010: As of version 0.8.40 Nginx now supports wsgi applications running over the uWSGI protocol natively. Click Here for more details. The 0.8.x branch is now the current stable branch.

Apache + mod_wsgi
One possible solution was to run Apache as a backend server listening on 127.0.0.1:8080 (or a port of your choice), which could also be easily used to serve up other dynamic content such as php. Many have used this setup for a great deal of internal load balancing, letting Nginx serve strictly static content, and Apache to handle the dynamic content.

In the sense of a WSGI Python application, you would have a server block like this in Nginx:

server {
	#server_name is what nginx responds to
	server_name  mydomain.com www.mydomain.com;
 
	location / {
		#setting a Host header is handy if you have apache
		#setup with name-based virtual hosts
		proxy_set_header Host mydomain.com;
 
		#requires nginx to be compiled with --with-http_realip_module
		proxy_set_header X-Real-IP $remote_addr;
 
		#This can also be the IP address of another server
		proxy_pass http://127.0.0.1:8080;
	}
}

With the above method you could go with the easy route of having mod_wsgi (as of this writing, mod_wsgi is available at 2.5 supporting Python 2.6) installed via Apache. However doubling up the number of webservers run, might defeat the purpose of running Nginx for some of us, especially for those less familiar with Apache configuration.

Nginx WSGI Module

There was a port of Apache’s mod_wsgi over to Nginx by Manlio Perillo. However this module had only been tested on Nginx 0.5.34, and patched for 0.6.*.

However even when patched, the module remained quite buggy. Implementing this module went something like this:

In the http { } block

    wsgi_python_optimize 0;
    wsgi_enable_subinterpreters on;

In your server { } block

server {
	listen 80;
	server_name yourdomain.com;
 
        location / {
            wsgi_pass  /var/www/username/domain/application.wsgi;
 
            include wsgi_vars;
 
            wsgi_var  SCRIPT_NAME         /var/www/username/domain/application.wsgi;
            wsgi_var  DOCUMENT_ROOT       /var/www/username/domain;
 
            wsgi_pass_authorization off;
            wsgi_script_reloading on;
            wsgi_use_main_interpreter on;
        }
}

This module is no longer maintained and is does not to build on modern versions of Nginx (0.7/0.8), and was barely compatible with 0.6 by using a patch. The creator of the Apache mod_wsgi, Graham Dumpleton commented on his blog regarding the Nginx implementation:


The nginx version of mod_wsgi borrows some code from my original Apache version, but obviously since the internals of Apache and nginx are very different, the main parts of the code which interface with the web server are unique. Although I condoned use of the source code, I do wish I had insisted from the outset that it not be called mod_wsgi due to the confusion that has at times arisen.

Although development on the nginx version of mod_wsgi appears to no longer be happening, this isn’t stopping people from using it and many are quite happy with it. The question is whether they really understand anything about how nginx works and the shortcomings in how nginx and mod_wsgi work together.

Admittedly the author of the mod_wsgi module for nginx has been up front in pointing out that because nginx is asynchronous, and with WSGI not designed for such a system, that once the WSGI application is entered all other activity by the web server is blocked. The recommendation resulting from this is that static files should not be served from the same web server. Use of multiple nginx worker processes is also suggested as a way of mitigating the problem.

Source: Graham Dumpleton: Blocking requests and nginx version of mod_wsgi

There is however a far more practical solution fit for production use, especially for those using modern versions of Nginx.