| 1 |
============================== |
|---|
| 2 |
How to use Django with FastCGI |
|---|
| 3 |
============================== |
|---|
| 4 |
|
|---|
| 5 |
Although the `current preferred setup`_ for running Django is Apache_ with |
|---|
| 6 |
`mod_python`_, many people use shared hosting, on which FastCGI is the only |
|---|
| 7 |
viable option. In some setups, FastCGI also allows better security -- and, |
|---|
| 8 |
possibly, better performance -- than mod_python. |
|---|
| 9 |
|
|---|
| 10 |
Essentially, FastCGI is an efficient way of letting an external application |
|---|
| 11 |
serve pages to a Web server. The Web server delegates the incoming Web requests |
|---|
| 12 |
(via a socket) to FastCGI, which executes the code and passes the response back |
|---|
| 13 |
to the Web server, which, in turn, passes it back to the client's Web browser. |
|---|
| 14 |
|
|---|
| 15 |
Like mod_python, FastCGI allows code to stay in memory, allowing requests to be |
|---|
| 16 |
served with no startup time. Unlike mod_python (or `mod_perl`_), a FastCGI |
|---|
| 17 |
process doesn't run inside the Web server process, but in a separate, |
|---|
| 18 |
persistent process. |
|---|
| 19 |
|
|---|
| 20 |
.. _current preferred setup: ../modpython/ |
|---|
| 21 |
.. _Apache: http://httpd.apache.org/ |
|---|
| 22 |
.. _mod_python: http://www.modpython.org/ |
|---|
| 23 |
.. _mod_perl: http://perl.apache.org/ |
|---|
| 24 |
|
|---|
| 25 |
.. admonition:: Why run code in a separate process? |
|---|
| 26 |
|
|---|
| 27 |
The traditional ``mod_*`` arrangements in Apache embed various scripting |
|---|
| 28 |
languages (most notably PHP, Python and Perl) inside the process space of |
|---|
| 29 |
your Web server. Although this lowers startup time -- because code doesn't |
|---|
| 30 |
have to be read off disk for every request -- it comes at the cost of |
|---|
| 31 |
memory use. For mod_python, for example, every Apache process gets its own |
|---|
| 32 |
Python interpreter, which uses up a considerable amount of RAM. |
|---|
| 33 |
|
|---|
| 34 |
Due to the nature of FastCGI, it's even possible to have processes that run |
|---|
| 35 |
under a different user account than the Web server process. That's a nice |
|---|
| 36 |
security benefit on shared systems, because it means you can secure your |
|---|
| 37 |
code from other users. |
|---|
| 38 |
|
|---|
| 39 |
Prerequisite: flup |
|---|
| 40 |
================== |
|---|
| 41 |
|
|---|
| 42 |
Before you can start using FastCGI with Django, you'll need to install flup_, |
|---|
| 43 |
which is a Python library for dealing with FastCGI. Make sure to use the latest |
|---|
| 44 |
Subversion snapshot of flup, as some users have reported stalled pages with |
|---|
| 45 |
older flup versions. |
|---|
| 46 |
|
|---|
| 47 |
.. _flup: http://www.saddi.com/software/flup/ |
|---|
| 48 |
|
|---|
| 49 |
Starting your FastCGI server |
|---|
| 50 |
============================ |
|---|
| 51 |
|
|---|
| 52 |
FastCGI operates on a client-server model, and in most cases you'll be starting |
|---|
| 53 |
the FastCGI process on your own. Your Web server (be it Apache, lighttpd, or |
|---|
| 54 |
otherwise) only contacts your Django-FastCGI process when the server needs a |
|---|
| 55 |
dynamic page to be loaded. Because the daemon is already running with the code |
|---|
| 56 |
in memory, it's able to serve the response very quickly. |
|---|
| 57 |
|
|---|
| 58 |
.. admonition:: Note |
|---|
| 59 |
|
|---|
| 60 |
If you're on a shared hosting system, you'll probably be forced to use |
|---|
| 61 |
Web server-managed FastCGI processes. See the section below on running |
|---|
| 62 |
Django with Web server-managed processes for more information. |
|---|
| 63 |
|
|---|
| 64 |
A Web server can connect to a FastCGI server in one of two ways: It can use |
|---|
| 65 |
either a Unix domain socket (a "named pipe" on Win32 systems), or it can use a |
|---|
| 66 |
TCP socket. What you choose is a manner of preference; a TCP socket is usually |
|---|
| 67 |
easier due to permissions issues. |
|---|
| 68 |
|
|---|
| 69 |
To start your server, first change into the directory of your project (wherever |
|---|
| 70 |
your ``manage.py`` is), and then run ``manage.py`` with the ``runfcgi`` option:: |
|---|
| 71 |
|
|---|
| 72 |
./manage.py runfcgi [options] |
|---|
| 73 |
|
|---|
| 74 |
If you specify ``help`` as the only option after ``runfcgi``, it'll display a |
|---|
| 75 |
list of all the available options. |
|---|
| 76 |
|
|---|
| 77 |
You'll need to specify either a ``socket`` or both ``host`` and ``port``. Then, |
|---|
| 78 |
when you set up your Web server, you'll just need to point it at the host/port |
|---|
| 79 |
or socket you specified when starting the FastCGI server. |
|---|
| 80 |
|
|---|
| 81 |
Examples |
|---|
| 82 |
-------- |
|---|
| 83 |
|
|---|
| 84 |
Running a threaded server on a TCP port:: |
|---|
| 85 |
|
|---|
| 86 |
./manage.py runfcgi method=threaded host=127.0.0.1 port=3033 |
|---|
| 87 |
|
|---|
| 88 |
Running a preforked server on a Unix domain socket:: |
|---|
| 89 |
|
|---|
| 90 |
./manage.py runfcgi method=prefork socket=/home/user/mysite.sock pidfile=django.pid |
|---|
| 91 |
|
|---|
| 92 |
Run without daemonizing (backgrounding) the process (good for debugging):: |
|---|
| 93 |
|
|---|
| 94 |
./manage.py runfcgi daemonize=false socket=/tmp/mysite.sock |
|---|
| 95 |
|
|---|
| 96 |
Stopping the FastCGI daemon |
|---|
| 97 |
--------------------------- |
|---|
| 98 |
|
|---|
| 99 |
If you have the process running in the foreground, it's easy enough to stop it: |
|---|
| 100 |
Simply hitting ``Ctrl-C`` will stop and quit the FastCGI server. However, when |
|---|
| 101 |
you're dealing with background processes, you'll need to resort to the Unix |
|---|
| 102 |
``kill`` command. |
|---|
| 103 |
|
|---|
| 104 |
If you specify the ``pidfile`` option to your ``manage.py runfcgi``, you can |
|---|
| 105 |
kill the running FastCGI daemon like this:: |
|---|
| 106 |
|
|---|
| 107 |
kill `cat $PIDFILE` |
|---|
| 108 |
|
|---|
| 109 |
...where ``$PIDFILE`` is the ``pidfile`` you specified. |
|---|
| 110 |
|
|---|
| 111 |
To easily restart your FastCGI daemon on Unix, try this small shell script:: |
|---|
| 112 |
|
|---|
| 113 |
#!/bin/bash |
|---|
| 114 |
|
|---|
| 115 |
# Replace these three settings. |
|---|
| 116 |
PROJDIR="/home/user/myproject" |
|---|
| 117 |
PIDFILE="$PROJDIR/mysite.pid" |
|---|
| 118 |
SOCKET="$PROJDIR/mysite.sock" |
|---|
| 119 |
|
|---|
| 120 |
cd $PROJDIR |
|---|
| 121 |
if [ -f $PIDFILE ]; then |
|---|
| 122 |
kill `cat -- $PIDFILE` |
|---|
| 123 |
rm -f -- $PIDFILE |
|---|
| 124 |
fi |
|---|
| 125 |
|
|---|
| 126 |
exec /usr/bin/env - \ |
|---|
| 127 |
PYTHONPATH="../python:.." \ |
|---|
| 128 |
./manage.py runfcgi socket=$SOCKET pidfile=$PIDFILE |
|---|
| 129 |
|
|---|
| 130 |
Apache setup |
|---|
| 131 |
============ |
|---|
| 132 |
|
|---|
| 133 |
To use Django with Apache and FastCGI, you'll need Apache installed and |
|---|
| 134 |
configured, with `mod_fastcgi`_ installed and enabled. Consult the Apache |
|---|
| 135 |
documentation for instructions. |
|---|
| 136 |
|
|---|
| 137 |
Once you've got that set up, point Apache at your Django FastCGI instance by |
|---|
| 138 |
editing the ``httpd.conf`` (Apache configuration) file. You'll need to do two |
|---|
| 139 |
things: |
|---|
| 140 |
|
|---|
| 141 |
* Use the ``FastCGIExternalServer`` directive to specify the location of |
|---|
| 142 |
your FastCGI server. |
|---|
| 143 |
* Use ``mod_rewrite`` to point URLs at FastCGI as appropriate. |
|---|
| 144 |
|
|---|
| 145 |
.. _mod_fastcgi: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html |
|---|
| 146 |
|
|---|
| 147 |
Specifying the location of the FastCGI server |
|---|
| 148 |
--------------------------------------------- |
|---|
| 149 |
|
|---|
| 150 |
The ``FastCGIExternalServer`` directive tells Apache how to find your FastCGI |
|---|
| 151 |
server. As the `FastCGIExternalServer docs`_ explain, you can specify either a |
|---|
| 152 |
``socket`` or a ``host``. Here are examples of both:: |
|---|
| 153 |
|
|---|
| 154 |
# Connect to FastCGI via a socket / named pipe. |
|---|
| 155 |
FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock |
|---|
| 156 |
|
|---|
| 157 |
# Connect to FastCGI via a TCP host/port. |
|---|
| 158 |
FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033 |
|---|
| 159 |
|
|---|
| 160 |
In either case, the file ``/home/user/public_html/mysite.fcgi`` doesn't |
|---|
| 161 |
actually have to exist. It's just a URL used by the Web server internally -- a |
|---|
| 162 |
hook for signifying which requests at a URL should be handled by FastCGI. (More |
|---|
| 163 |
on this in the next section.) |
|---|
| 164 |
|
|---|
| 165 |
.. _FastCGIExternalServer docs: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html#FastCgiExternalServer |
|---|
| 166 |
|
|---|
| 167 |
Using mod_rewrite to point URLs at FastCGI |
|---|
| 168 |
------------------------------------------ |
|---|
| 169 |
|
|---|
| 170 |
The second step is telling Apache to use FastCGI for URLs that match a certain |
|---|
| 171 |
pattern. To do this, use the `mod_rewrite`_ module and rewrite URLs to |
|---|
| 172 |
``mysite.fcgi`` (or whatever you specified in the ``FastCGIExternalServer`` |
|---|
| 173 |
directive, as explained in the previous section). |
|---|
| 174 |
|
|---|
| 175 |
In this example, we tell Apache to use FastCGI to handle any request that |
|---|
| 176 |
doesn't represent a file on the filesystem and doesn't start with ``/media/``. |
|---|
| 177 |
This is probably the most common case, if you're using Django's admin site:: |
|---|
| 178 |
|
|---|
| 179 |
<VirtualHost 12.34.56.78> |
|---|
| 180 |
ServerName example.com |
|---|
| 181 |
DocumentRoot /home/user/public_html |
|---|
| 182 |
Alias /media /home/user/python/django/contrib/admin/media |
|---|
| 183 |
RewriteEngine On |
|---|
| 184 |
RewriteRule ^/(media.*)$ /$1 [QSA,L] |
|---|
| 185 |
RewriteCond %{REQUEST_FILENAME} !-f |
|---|
| 186 |
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L] |
|---|
| 187 |
</VirtualHost> |
|---|
| 188 |
|
|---|
| 189 |
.. _mod_rewrite: http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html |
|---|
| 190 |
|
|---|
| 191 |
lighttpd setup |
|---|
| 192 |
============== |
|---|
| 193 |
|
|---|
| 194 |
lighttpd is a lightweight Web server commonly used for serving static files. It |
|---|
| 195 |
supports FastCGI natively and, thus, is a good choice for serving both static |
|---|
| 196 |
and dynamic pages, if your site doesn't have any Apache-specific needs. |
|---|
| 197 |
|
|---|
| 198 |
Make sure ``mod_fastcgi`` is in your modules list, somewhere after |
|---|
| 199 |
``mod_rewrite`` and ``mod_access``, but not after ``mod_accesslog``. You'll |
|---|
| 200 |
probably want ``mod_alias`` as well, for serving admin media. |
|---|
| 201 |
|
|---|
| 202 |
Add the following to your lighttpd config file:: |
|---|
| 203 |
|
|---|
| 204 |
server.document-root = "/home/user/public_html" |
|---|
| 205 |
fastcgi.server = ( |
|---|
| 206 |
"/mysite.fcgi" => ( |
|---|
| 207 |
"main" => ( |
|---|
| 208 |
# Use host / port instead of socket for TCP fastcgi |
|---|
| 209 |
# "host" => "127.0.0.1", |
|---|
| 210 |
# "port" => 3033, |
|---|
| 211 |
"socket" => "/home/user/mysite.sock", |
|---|
| 212 |
"check-local" => "disable", |
|---|
| 213 |
) |
|---|
| 214 |
), |
|---|
| 215 |
) |
|---|
| 216 |
alias.url = ( |
|---|
| 217 |
"/media/" => "/home/user/django/contrib/admin/media/", |
|---|
| 218 |
) |
|---|
| 219 |
|
|---|
| 220 |
url.rewrite-once = ( |
|---|
| 221 |
"^(/media.*)$" => "$1", |
|---|
| 222 |
"^/favicon\.ico$" => "/media/favicon.ico", |
|---|
| 223 |
"^(/.*)$" => "/mysite.fcgi$1", |
|---|
| 224 |
) |
|---|
| 225 |
|
|---|
| 226 |
Running multiple Django sites on one lighttpd |
|---|
| 227 |
--------------------------------------------- |
|---|
| 228 |
|
|---|
| 229 |
lighttpd lets you use "conditional configuration" to allow configuration to be |
|---|
| 230 |
customized per host. To specify multiple FastCGI sites, just add a conditional |
|---|
| 231 |
block around your FastCGI config for each site:: |
|---|
| 232 |
|
|---|
| 233 |
# If the hostname is 'www.example1.com'... |
|---|
| 234 |
$HTTP["host"] == "www.example1.com" { |
|---|
| 235 |
server.document-root = "/foo/site1" |
|---|
| 236 |
fastcgi.server = ( |
|---|
| 237 |
... |
|---|
| 238 |
) |
|---|
| 239 |
... |
|---|
| 240 |
} |
|---|
| 241 |
|
|---|
| 242 |
# If the hostname is 'www.example2.com'... |
|---|
| 243 |
$HTTP["host"] == "www.example2.com" { |
|---|
| 244 |
server.document-root = "/foo/site2" |
|---|
| 245 |
fastcgi.server = ( |
|---|
| 246 |
... |
|---|
| 247 |
) |
|---|
| 248 |
... |
|---|
| 249 |
} |
|---|
| 250 |
|
|---|
| 251 |
You can also run multiple Django installations on the same site simply by |
|---|
| 252 |
specifying multiple entries in the ``fastcgi.server`` directive. Add one |
|---|
| 253 |
FastCGI host for each. |
|---|
| 254 |
|
|---|
| 255 |
Running Django on a shared-hosting provider with Apache |
|---|
| 256 |
======================================================= |
|---|
| 257 |
|
|---|
| 258 |
Many shared-hosting providers don't allow you to run your own server daemons or |
|---|
| 259 |
edit the ``httpd.conf`` file. In these cases, it's still possible to run Django |
|---|
| 260 |
using Web server-spawned processes. |
|---|
| 261 |
|
|---|
| 262 |
.. admonition:: Note |
|---|
| 263 |
|
|---|
| 264 |
If you're using Web server-spawned processes, as explained in this section, |
|---|
| 265 |
there's no need for you to start the FastCGI server on your own. Apache |
|---|
| 266 |
will spawn a number of processes, scaling as it needs to. |
|---|
| 267 |
|
|---|
| 268 |
In your Web root directory, add this to a file named ``.htaccess`` :: |
|---|
| 269 |
|
|---|
| 270 |
AddHandler fastcgi-script .fcgi |
|---|
| 271 |
RewriteEngine On |
|---|
| 272 |
RewriteCond %{REQUEST_FILENAME} !-f |
|---|
| 273 |
RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L] |
|---|
| 274 |
|
|---|
| 275 |
Then, create a small script that tells Apache how to spawn your FastCGI |
|---|
| 276 |
program. Create a file ``mysite.fcgi`` and place it in your Web directory, and |
|---|
| 277 |
be sure to make it executable:: |
|---|
| 278 |
|
|---|
| 279 |
#!/usr/bin/python |
|---|
| 280 |
import sys, os |
|---|
| 281 |
|
|---|
| 282 |
# Add a custom Python path. |
|---|
| 283 |
sys.path.insert(0, "/home/user/python") |
|---|
| 284 |
|
|---|
| 285 |
# Switch to the directory of your project. (Optional.) |
|---|
| 286 |
# os.chdir("/home/user/myproject") |
|---|
| 287 |
|
|---|
| 288 |
# Set the DJANGO_SETTINGS_MODULE environment variable. |
|---|
| 289 |
os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings" |
|---|
| 290 |
|
|---|
| 291 |
from django.core.servers.fastcgi import runfastcgi |
|---|
| 292 |
runfastcgi(method="threaded", daemonize="false") |
|---|
| 293 |
|
|---|
| 294 |
Restarting the spawned server |
|---|
| 295 |
----------------------------- |
|---|
| 296 |
|
|---|
| 297 |
If you change any Python code on your site, you'll need to tell FastCGI the |
|---|
| 298 |
code has changed. But there's no need to restart Apache in this case. Rather, |
|---|
| 299 |
just reupload ``mysite.fcgi``, or edit the file, so that the timestamp on the |
|---|
| 300 |
file will change. When Apache sees the file has been updated, it will restart |
|---|
| 301 |
your Django application for you. |
|---|
| 302 |
|
|---|
| 303 |
If you have access to a command shell on a Unix system, you can accomplish this |
|---|
| 304 |
easily by using the ``touch`` command:: |
|---|
| 305 |
|
|---|
| 306 |
touch mysite.fcgi |
|---|
| 307 |
|
|---|
| 308 |
Serving admin media files |
|---|
| 309 |
========================= |
|---|
| 310 |
|
|---|
| 311 |
Regardless of the server and configuration you eventually decide to use, you will |
|---|
| 312 |
also need to give some thought to how to serve the admin media files. The |
|---|
| 313 |
advice given in the modpython_ documentation is also applicable in the setups |
|---|
| 314 |
detailed above. |
|---|
| 315 |
|
|---|
| 316 |
.. _modpython: ../modpython/#serving-the-admin-files |
|---|