Вы находитесь на странице: 1из 7

Servers — Django Best Practices http://lincolnloop.com/django-best-practices/deplo...

Blog (/blog/)
Contact (#jump)
Existing Clients (#jump)

(/)

Agile web development for


businesses and creative firms
Exceptional applications built
using the Django web framework

Servers
Note

Deployment arcitectures vary widely depending on the needs and traffic of the site. The setup described
below works best for us in most instances.

We serve Django on Linux with a PostgreSQL database backend via Apache and mod_wsgi
(http://www.modwsgi.org) from behind an Nginx (http://nginx.net) instance acting as a frontend proxy.

Nginx
Nginx (http://nginx.net) makes for a great frontend server due to its speed, stability and low resource
footprint. The typical Nginx configuration for a site looks like this:

1 of 7 08/24/2010 09:28 PM
Servers — Django Best Practices http://lincolnloop.com/django-best-practices/deplo...

# Apache server
upstream django {
server domain.com:9000;
}

# Redirect all requests on the www subdomain to the root domain


server {
listen 80;
server_name www.domain.com;
rewrite ^/(.*) http://domain.com/$1 permanent;
}

# Serve static files and redirect any other request to Apache


server {
listen 80;
server_name domain.com;
root /var/www/domain.com/;
access_log /var/log/nginx/domain.com.access.log;

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;

if (!-f $request_filename) {
proxy_pass http://django;
}
}

What Does it Do?

The first block tells Nginx where to find the server hosting our Django site. The second block redirects any
request coming in on www.domain.com to domain.com so each resource has only one URL that will
access it. The final block is the one that does all the work. It tells Nginx to check if a file matching the
request exists in /var/www/domain.com. If it does, it serves that file, if it doesn’t, it proxies the request to
the Django site.

SSL

Another benefit to running a frontend server is lightweight SSL proxying. Rather than having two Django
instances running for SSL and non-SSL access, we can have Nginx act as the gatekeeper redirecting all
requests back to a single non-SSL Apache instance listening on the localhost. Here’s what that would
look like:

2 of 7 08/24/2010 09:28 PM
Servers — Django Best Practices http://lincolnloop.com/django-best-practices/deplo...

server {
listen 67.207.128.83:443; #replace with your own ip address
server_name domain.com;
root /var/www/domain.com/;
access_log /var/log/nginx/domain.com.access.log;

ssl on;
ssl_certificate /etc/nginx/ssl/certs/domain.com.crt;
ssl_certificate_key /etc/nginx/ssl/private/domain.com.key;
ssl_prefer_server_ciphers on;

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;
proxy_set_header X-Forwarded-Protocol https;

if (!-f $request_filename) {
proxy_pass http://django;
}

You can include this code at the bottom of your non-SSL configuration file.

Tip

For SSL-aware Django sites like Satchmo (http://www.satchmoproject.com), you’ll need to “trick” the site
into thinking incoming requests are coming in via SSL, but this is simple enough to do with a small
addition to the WSGI script (http://gist.github.com/78416) we discuss below.

Apache
We run the Apache2 Worker MPM with mod_wsgi (http://www.modwsgi.org) in daemon mode. The default
settings for the MPM Worker module should be sufficient for most environments although those with a
shortage of RAM may want to look into reducing the number of servers spawned. Since Nginx will be
listening for HTTP(S) requests, you’ll need to bind Apache to a different port. While you’re at it, you can tell
it to only respond to the localhost. To do so, you’ll want to edit the Listen directive
(http://httpd.apache.org/docs/2.2/mod/mpm_common.html#listen)

Listen 127.0.0.1:9000

With Apache up and running, you’ll need an Apache configuration and WSGI script for each site. A typical
Apache configuration for an individual site looks like this:

3 of 7 08/24/2010 09:28 PM
Servers — Django Best Practices http://lincolnloop.com/django-best-practices/deplo...

<VirtualHost *:9000>
ServerName domain.com
ServerAdmin webmaster@domain.com
ErrorLog /var/log/apache2/domain.com.log

WSGIDaemonProcess domain display-name=%{GROUP} maximum-requests=10000


WSGIProcessGroup domain

WSGIScriptAlias / /opt/webapps/domain.com/apache/django.wsgi

<Directory /opt/webapps/domain.com/apache>
Order deny,allow
Allow from all
</Directory>
</VirtualHost>

Tip

In a perfect world, your app would never leak memory and you can leave out the maximum-requests
directive. In our experience, setting this to a high number is nice to keep Apache’s memory usage in
check.

Warning

This will default to a single process with 15 threads. Django is not “officially” thread safe and some
external libraries (notably a couple required for django.contrib.gis) are known to not be thread
safe. If needed the threads and processes arguments can be adjusted accordingly.

It links to the WSGI script within the project directory. The script is just a few lines of Python to properly
setup our environment.

4 of 7 08/24/2010 09:28 PM
Servers — Django Best Practices http://lincolnloop.com/django-best-practices/deplo...

import os, sys


import site

# put virtualenv on pythonpath


site.addsitedir('/opt/webapps/domain.com/lib/python2.5/site-packages')

# redirect print statements to apache log


sys.stdout = sys.stderr

os.environ['DJANGO_SETTINGS_MODULE'] = 'domain.settings'

import django.core.handlers.wsgi

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

Add New Comment

Type your comment here.

Post as …

Showing 4 comments

Sort by Popular now Subscribe by email (#) Subscribe by RSS (http://django-

best-practices.disqus.com/servers_mdash_django_best_practices/latest.rss)

MikeMike 2 months ago (#comment-57839721)


(http://disqus.com/guest
/8d555d6c68c850e2bd3d4639025f1f7c/)

Very well done. Thanks for putting that up there. Finding this site was like finding a delicious cheese cake in my
pants pocket, but without the mess.

1 person liked this. Like Reply

Graham Dumpleton 1 week ago (#comment-67678795)

5 of 7 08/24/2010 09:28 PM
Servers — Django Best Practices http://lincolnloop.com/django-best-practices/deplo...

(http://disqus.com/guest
/70dfb4afd84b106d0855184bf0ae4675/)

Also, rather that the fixup to WSGI script to make Django know original request was SSL, you are better off just
adding to Apache configuration:

SetEnvIf X-Forwarded-Protocol "^https$" HTTPS=on

Like Reply

Graham Dumpleton 1 week ago (#comment-67673988)


(http://disqus.com/guest
/70dfb4afd84b106d0855184bf0ae4675/)

Note that mapping stdout to stderr is not needed if using mod_wsgi 3.X or later. Gave up trying to make people
write portable WSGI code and so removed default restriction on accessing stding/stdout. See
'http://blog.dscpl.com.au/2009/04/wsgi-and-printing-to-standard-output.html'.

Like Reply

Marco Rogers (http://marcorogers.com/) 1 year ago (#comment-8674106)


(http://disqus.com
/polotek/)

This is awesome. This is exactly the kind of server config info I needed. I muddled through this and got it working
on my own after finding the online resources lacking. But there are a few key points here that I missed.

Like Reply

blog comments powered by DISQUS (http://disqus.com)

Table Of Contents (../index.html)

Servers (#)
Nginx (#nginx)
SSL (#ssl)
Apache (#apache)

Previous topic

Project Bootstrapping (bootstrap.html)

Quick search

Go

6 of 7 08/24/2010 09:28 PM
Servers — Django Best Practices http://lincolnloop.com/django-best-practices/deplo...

Enter search terms or a module, class or function name.

Billing (https://lincolnloop.freshbooks.com)
Basecamp (https://lincolnloop.grouphub.com)
Email/Hosting Support (https://www.websitesettings.com) or 877.934.0408

Interested in working with us?


Fill out the form below or contact us at:

ph: 970.879.8810
PO Box 774441
fx: 970.367.8596
Steamboat Springs, CO
info@lincolnloop.com (mailto:info@lincolnloop.com)
80477
Name

required

Phone
Email

required

Request
Note

required

Submit

7 of 7 08/24/2010 09:28 PM

Вам также может понравиться