| ============================== |
| How to use Django with FastCGI |
| ============================== |
| |
| Although the `current preferred setup`_ for running Django is Apache_ with |
| `mod_python`_, many people use shared hosting, on which FastCGI is the only |
| viable option. In some setups, FastCGI also allows better security -- and, |
| possibly, better performance -- than mod_python. |
| |
| Essentially, FastCGI is an efficient way of letting an external application |
| serve pages to a Web server. The Web server delegates the incoming Web requests |
| (via a socket) to FastCGI, which executes the code and passes the response back |
| to the Web server, which, in turn, passes it back to the client's Web browser. |
| |
| Like mod_python, FastCGI allows code to stay in memory, allowing requests to be |
| served with no startup time. Unlike mod_python (or `mod_perl`_), a FastCGI |
| process doesn't run inside the Web server process, but in a separate, |
| persistent process. |
| |
| .. _current preferred setup: ../modpython/ |
| .. _Apache: http://httpd.apache.org/ |
| .. _mod_python: http://www.modpython.org/ |
| .. _mod_perl: http://perl.apache.org/ |
| |
| .. admonition:: Why run code in a separate process? |
| |
| The traditional ``mod_*`` arrangements in Apache embed various scripting |
| languages (most notably PHP, Python and Perl) inside the process space of |
| your Web server. Although this lowers startup time -- because code doesn't |
| have to be read off disk for every request -- it comes at the cost of |
| memory use. For mod_python, for example, every Apache process gets its own |
| Python interpreter, which uses up a considerable amount of RAM. |
| |
| Due to the nature of FastCGI, it's even possible to have processes that run |
| under a different user account than the Web server process. That's a nice |
| security benefit on shared systems, because it means you can secure your |
| code from other users. |
| |
| Prerequisite: flup |
| ================== |
| |
| Before you can start using FastCGI with Django, you'll need to install flup_, |
| which is a Python library for dealing with FastCGI. Make sure to use the latest |
| Subversion snapshot of flup, as some users have reported stalled pages with |
| older flup versions. |
| |
| .. _flup: http://www.saddi.com/software/flup/ |
| |
| Starting your FastCGI server |
| ============================ |
| |
| FastCGI operates on a client-server model, and in most cases you'll be starting |
| the FastCGI process on your own. Your Web server (be it Apache, lighttpd, or |
| otherwise) only contacts your Django-FastCGI process when the server needs a |
| dynamic page to be loaded. Because the daemon is already running with the code |
| in memory, it's able to serve the response very quickly. |
| |
| .. admonition:: Note |
| |
| If you're on a shared hosting system, you'll probably be forced to use |
| Web server-managed FastCGI processes. See the section below on running |
| Django with Web server-managed processes for more information. |
| |
| A Web server can connect to a FastCGI server in one of two ways: It can use |
| either a Unix domain socket (a "named pipe" on Win32 systems), or it can use a |
| TCP socket. What you choose is a manner of preference; a TCP socket is usually |
| easier due to permissions issues. |
| |
| To start your server, first change into the directory of your project (wherever |
| your ``manage.py`` is), and then run ``manage.py`` with the ``runfcgi`` option:: |
| |
| ./manage.py runfcgi [options] |
| |
| If you specify ``help`` as the only option after ``runfcgi``, it'll display a |
| list of all the available options. |
| |
| You'll need to specify either a ``socket`` or both ``host`` and ``port``. Then, |
| when you set up your Web server, you'll just need to point it at the host/port |
| or socket you specified when starting the FastCGI server. |
| |
| Examples |
| -------- |
| |
| Running a threaded server on a TCP port:: |
| |
| ./manage.py runfcgi method=threaded host=127.0.0.1 port=3033 |
| |
| Running a preforked server on a Unix domain socket:: |
| |
| ./manage.py runfcgi method=prefork socket=/home/user/mysite.sock pidfile=django.pid |
| |
| Run without daemonizing (backgrounding) the process (good for debugging):: |
| |
| ./manage.py runfcgi daemonize=false socket=/tmp/mysite.sock |
| |
| Stopping the FastCGI daemon |
| --------------------------- |
| |
| If you have the process running in the foreground, it's easy enough to stop it: |
| Simply hitting ``Ctrl-C`` will stop and quit the FastCGI server. However, when |
| you're dealing with background processes, you'll need to resort to the Unix |
| ``kill`` command. |
| |
| If you specify the ``pidfile`` option to your ``manage.py runfcgi``, you can |
| kill the running FastCGI daemon like this:: |
| |
| kill `cat $PIDFILE` |
| |
| ...where ``$PIDFILE`` is the ``pidfile`` you specified. |
| |
| To easily restart your FastCGI daemon on Unix, try this small shell script:: |
| |
| #!/bin/bash |
| |
| # Replace these three settings. |
| PROJDIR="/home/user/myproject" |
| PIDFILE="$PROJDIR/mysite.pid" |
| SOCKET="$PROJDIR/mysite.sock" |
| |
| cd $PROJDIR |
| if [ -f $PIDFILE ]; then |
| kill `cat -- $PIDFILE` |
| rm -f -- $PIDFILE |
| fi |
| |
| exec /usr/bin/env - \ |
| PYTHONPATH="../python:.." \ |
| ./manage.py runfcgi socket=$SOCKET pidfile=$PIDFILE |
| |
| Apache setup |
| ============ |
| |
| To use Django with Apache and FastCGI, you'll need Apache installed and |
| configured, with `mod_fastcgi`_ installed and enabled. Consult the Apache |
| documentation for instructions. |
| |
| Once you've got that set up, point Apache at your Django FastCGI instance by |
| editing the ``httpd.conf`` (Apache configuration) file. You'll need to do two |
| things: |
| |
| * Use the ``FastCGIExternalServer`` directive to specify the location of |
| your FastCGI server. |
| * Use ``mod_rewrite`` to point URLs at FastCGI as appropriate. |
| |
| .. _mod_fastcgi: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html |
| |
| Specifying the location of the FastCGI server |
| --------------------------------------------- |
| |
| The ``FastCGIExternalServer`` directive tells Apache how to find your FastCGI |
| server. As the `FastCGIExternalServer docs`_ explain, you can specify either a |
| ``socket`` or a ``host``. Here are examples of both:: |
| |
| # Connect to FastCGI via a socket / named pipe. |
| FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock |
| |
| # Connect to FastCGI via a TCP host/port. |
| FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033 |
| |
| In either case, the file ``/home/user/public_html/mysite.fcgi`` doesn't |
| actually have to exist. It's just a URL used by the Web server internally -- a |
| hook for signifying which requests at a URL should be handled by FastCGI. (More |
| on this in the next section.) |
| |
| .. _FastCGIExternalServer docs: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html#FastCgiExternalServer |
| |
| Using mod_rewrite to point URLs at FastCGI |
| ------------------------------------------ |
| |
| The second step is telling Apache to use FastCGI for URLs that match a certain |
| pattern. To do this, use the `mod_rewrite`_ module and rewrite URLs to |
| ``mysite.fcgi`` (or whatever you specified in the ``FastCGIExternalServer`` |
| directive, as explained in the previous section). |
| |
| In this example, we tell Apache to use FastCGI to handle any request that |
| doesn't represent a file on the filesystem and doesn't start with ``/media/``. |
| This is probably the most common case, if you're using Django's admin site:: |
| |
| <VirtualHost 12.34.56.78> |
| ServerName example.com |
| DocumentRoot /home/user/public_html |
| Alias /media /home/user/python/django/contrib/admin/media |
| RewriteEngine On |
| RewriteRule ^/(media.*)$ /$1 [QSA,L] |
| RewriteCond %{REQUEST_FILENAME} !-f |
| RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L] |
| </VirtualHost> |
| |
| .. _mod_rewrite: http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html |
| |
| lighttpd setup |
| ============== |
| |
| lighttpd is a lightweight Web server commonly used for serving static files. It |
| supports FastCGI natively and, thus, is a good choice for serving both static |
| and dynamic pages, if your site doesn't have any Apache-specific needs. |
| |
| Make sure ``mod_fastcgi`` is in your modules list, somewhere after |
| ``mod_rewrite`` and ``mod_access``, but not after ``mod_accesslog``. You'll |
| probably want ``mod_alias`` as well, for serving admin media. |
| |
| Add the following to your lighttpd config file:: |
| |
| server.document-root = "/home/user/public_html" |
| fastcgi.server = ( |
| "/mysite.fcgi" => ( |
| "main" => ( |
| # Use host / port instead of socket for TCP fastcgi |
| # "host" => "127.0.0.1", |
| # "port" => 3033, |
| "socket" => "/home/user/mysite.sock", |
| "check-local" => "disable", |
| ) |
| ), |
| ) |
| alias.url = ( |
| "/media/" => "/home/user/django/contrib/admin/media/", |
| ) |
| |
| url.rewrite-once = ( |
| "^(/media.*)$" => "$1", |
| "^/favicon\.ico$" => "/media/favicon.ico", |
| "^(/.*)$" => "/mysite.fcgi$1", |
| ) |
| |
| Running multiple Django sites on one lighttpd |
| --------------------------------------------- |
| |
| lighttpd lets you use "conditional configuration" to allow configuration to be |
| customized per host. To specify multiple FastCGI sites, just add a conditional |
| block around your FastCGI config for each site:: |
| |
| # If the hostname is 'www.example1.com'... |
| $HTTP["host"] == "www.example1.com" { |
| server.document-root = "/foo/site1" |
| fastcgi.server = ( |
| ... |
| ) |
| ... |
| } |
| |
| # If the hostname is 'www.example2.com'... |
| $HTTP["host"] == "www.example2.com" { |
| server.document-root = "/foo/site2" |
| fastcgi.server = ( |
| ... |
| ) |
| ... |
| } |
| |
| You can also run multiple Django installations on the same site simply by |
| specifying multiple entries in the ``fastcgi.server`` directive. Add one |
| FastCGI host for each. |
| |
| Running Django on a shared-hosting provider with Apache |
| ======================================================= |
| |
| Many shared-hosting providers don't allow you to run your own server daemons or |
| edit the ``httpd.conf`` file. In these cases, it's still possible to run Django |
| using Web server-spawned processes. |
| |
| .. admonition:: Note |
| |
| If you're using Web server-spawned processes, as explained in this section, |
| there's no need for you to start the FastCGI server on your own. Apache |
| will spawn a number of processes, scaling as it needs to. |
| |
| In your Web root directory, add this to a file named ``.htaccess`` :: |
| |
| AddHandler fastcgi-script .fcgi |
| RewriteEngine On |
| RewriteCond %{REQUEST_FILENAME} !-f |
| RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L] |
| |
| Then, create a small script that tells Apache how to spawn your FastCGI |
| program. Create a file ``mysite.fcgi`` and place it in your Web directory, and |
| be sure to make it executable:: |
| |
| #!/usr/bin/python |
| import sys, os |
| |
| # Add a custom Python path. |
| sys.path.insert(0, "/home/user/python") |
| |
| # Switch to the directory of your project. (Optional.) |
| # os.chdir("/home/user/myproject") |
| |
| # Set the DJANGO_SETTINGS_MODULE environment variable. |
| os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings" |
| |
| from django.core.servers.fastcgi import runfastcgi |
| runfastcgi(method="threaded", daemonize="false") |
| |
| Restarting the spawned server |
| ----------------------------- |
| |
| If you change any Python code on your site, you'll need to tell FastCGI the |
| code has changed. But there's no need to restart Apache in this case. Rather, |
| just reupload ``mysite.fcgi``, or edit the file, so that the timestamp on the |
| file will change. When Apache sees the file has been updated, it will restart |
| your Django application for you. |
| |
| If you have access to a command shell on a Unix system, you can accomplish this |
| easily by using the ``touch`` command:: |
| |
| touch mysite.fcgi |
| |
| Serving admin media files |
| ========================= |
| |
| Regardless of the server and configuration you eventually decide to use, you will |
| also need to give some thought to how to serve the admin media files. The |
| advice given in the modpython_ documentation is also applicable in the setups |
| detailed above. |
| |
| .. _modpython: ../modpython/#serving-the-admin-files |
| |