El libro de Django 1.0

20.4. Usando Django con FastCGI

Aunque Django bajo Apache y mod_python es la configuración más robusta de implementación, mucha gente usa hosting compartido, en los que FastCGI es la única opción de implementación.

Adicionalmente, en algunas situaciones, FastCGI permite mayor seguridad y posiblemente un mejor rendimiento que mod_python. Para sitios pequeños, FastCGI además puede ser más liviano que Apache.

20.4.1. Descripción de FastCGI

FastCGI es una manera eficiente de dejar que una aplicación externa genere páginas para un servidor Web. El servidor delega las peticiones Web entrantes ( a través de un socket) a FastCGI, quien ejecuta el código y devuelve la respuesta al servidor, quien, a su turno, la remitirá al navegador del cliente.

Como mod_python, FastCGI permite que el código permanezca en memoria, logrando que las peticiones sean servidas sin tiempo de inicialización. A diferencia de mod_python, un proceso FastCGI no corre dentro del proceso del servidor Web, sino en un proceso separado y persistente.

Antes de que puedas empezar a usar FastCGI con Django, necesitas instalar flup, una librería Python para manejar FastCGI. Algunos usuarios han reportado páginas que explotaron con versiones antiguas de flup, por lo cual puedes querer utilizar la última versión SVN. Puedes conseguir flup en http://www.djangoproject.com/r/flup/.

20.4.2. Ejecutando tu Servidor FastCGI

FastCGI opera sobre un modelo cliente/servidor, y en la mayoría de los casos estarás iniciando el proceso servidor FastCGI por tu cuenta. Tu servidor Web (ya sea Apache, lighttpd, o algún otro) hace contacto con tu proceso Django- FastCGI solo cuando el servidor necesita cargar una página dinámica. Como el demonio ya está ejecutando su código en memoria, puede servir la respuesta muy rápido.

Nota Si estás en un sistema de hosting compartido, probablemente estés forzado a usar procesos FastCGI manejados por el Web server. Si estás en esta situación, debes leer la sección titulada "Ejecutando Django en un proveedor de Hosting compartido con Apache_", más abajo.

Un servidor Web puede conectarse a un servidor FastCGI de dos formas: usando un socket de dominio Unix, (un named pipe en sistemas Win32) o un socket TCP. Lo que elijas es una cuestión de preferencias; normalmente un socket TCP es más fácil debido a cuestiones de permisos.

Para iniciar tu servidor, primero cambia al directorio de tu proyecto (donde está tu manage.py), y ejecuta manage.py con el comando runfcgi:

$ ./manage.py runfcgi [options]

Si especificas help como única opción después de runfcgi, se mostrará una lista de todas las opciones disponibles.

Necesitarás especificar un socket o si no host y port. Entonces, cuando configures tu servidor Web, solo necesitas apuntarlo al socket o host/port que especificaste cuando iniciaste el servidor FastCGI.

Algunos ejemplos pueden ayudar a explicarlo:

Ejecutar un servidor 'threaded' en un puerto TCP:

$ ./manage.py runfcgi method=threaded host=127.0.0.1 port=3033

Ejecutar un servidor preforked sobre un socket de dominio Unix:

$ ./manage.py runfcgi method=prefork socket=/home/user/mysite.sock pidfile=django.pid

Ejecutar sin demonizar (ejecutar en segundo plano) el proceso (es bueno para el debugging):

$ ./manage.py runfcgi daemonize=false socket=/tmp/mysite.sock

20.4.2.1. Detener el Demonio FastCGI

Si tienes el proceso ejecutando en primer plano, es fácil detenerlo: simplemente presiona Ctrl+C para detenerlo y salir del servidor FastCGI. Si estás tratando con procesos en segundo plano, necesitarás recurrir al comando kill de Unix.

Si especificas la opción pidfile en manage.py runfcgi, puedes detener el demonio FastCGI en ejecución de esta forma:

$ kill `cat $PIDFILE`

donde $PIDFILE es el pidfile que especificaste.

Para reiniciar con facilidad tu demonio FastCGI en Unix, pedes usar este breve script en la línea de comandos:

#!/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

20.4.3. Usando Django con Apache y FastCGI

Para usar Django con Apache y FastCGI, necesitarás que Apache esté instalado y configurado, con mod_fastcgi instalado y habilitado. Consulta la documentación de Apache y mod_fastcgi para instrucciones detalladas: http://www.djangoproject.com/r/mod_fastcgi/.

Una vez que hayas completado la configuración, apunta Apache a tu instancia FastCGI de Django editando el archivo httpd.conf (de la configuración de Apache). Necesitarás hacer dos cosas:

  • Usar la directiva FastCGIExternalServer para especificar la localización de tu servidor FastCGI.
  • Usar mod_rewrite para apuntar las URLs a FastCGI según sea necesario.

20.4.3.1. Especificando la Localización del Servidor FastCGI

La directiva FastCGIExternalServer le dice a Apache como encontrar tu servidor FastCGI. Como se explica en los documentos de FastCGIExternalServer (http://www.djangoproject.com/r/mod_fastcgi/FastCGIExternalServer/), puedes especificar un socket o un host. Aquí hay ejemplos de ambos:

Conectar con FastCGI mediante un socket o un pipe con nombre:

FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/
mysite.sock

Conectar con FastCGI mediante TCP:

FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033

En los dos casos, el directorio /home/user/public_html/ debe existir, aunque el archivo /home/user/public_html/mysite.fcgi no necesariamente tiene que existir. Es solo una URL usada por el servidor Web internamente -- un enganche para indicar que las consultas en esa URL deben ser manejadas por FastCGI. (Más sobre esto en la siguiente sección.)

20.4.3.2. Usando mod_rewrite para apuntar URLs hacia FastCGI

El segundo paso es decirle a Apache que use FastCGI para las URLS que coincidan con cierto patrón. PAra hacer esto, usa el módulo mod_rewrite y reescribe las URLs hacia mysite.fcgi (o donde hayas especificado en la directiva FastCGIExternalServer, como se explicó en la sección anterior).

En este ejemplo, le decimos a Apache que use FastCGI para manejar cualquier consulta que no represente un archivo del sistema de archivos y no empiece con /media/. Probablemente éste sea el caso más común, si estás usando el sitio de administración de Django:

<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>

20.4.4. FastCGI y lighttpd

lighttpd (http://www.djangoproject.com/r/lighttpd/) es un servidor Web liviano usado habitualmente para servir archivos estáticos. Admite FastCGI en forma nativa y por lo tanto es también una opción ideal para servir tanto páginas estáticas como dinámicas, si tu sitio no tiene necesidades específicas de Apache.

Asegúrate que mod_fastcgi está en tu lista de modulos, en algún lugar después de mod_rewrite y mod_access, y antes de mod_accesslog. Probablemente desees también mod_alias, para servir medios de administración.

Agrega lo siguiente a tu archivo de configuración de lighttpd:

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",
)

20.4.4.1. Ejecutando Múltiples Sitios Django en Una Instancia lighttpd

lighttpd te permite usar "configuración condicional" para permitir la configuración personalizada para cada host. Para especificar múltiples sitios FastCGI, solo agrega un bloque condicional en torno a tu configuración FastCGI para cada sitio:

# 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 = (
       ...
    )
    ...
}

Puedes también ejecutar múltiples instalaciones de Django en el mismo sitio simplemente especificando múltiples entradas en la directiva fastcgi.server. Agrega un host FastCGI para cada una.

20.4.5. Ejecutando Django en un Proveedor de Hosting Compartido con Apache

Muchos proveedores de hosting compartido no te permiten ejecutar tus propios demonios servidores o editar el archivo httpd.conf. En estos casos, aún es posible ejecutar Django usando procesos iniciados por el sevidor Web.

Nota Si estás usando procesos iniciados por el servidor Web, como se explica en esta sección, no necesitas iniciar el servidor FastCGI por tu cuenta. Apache iniciará una cantidad de procesos, escalando según lo necesite.

En el directorio raíz de tu Web, agrega esto a un archivo llamado .htaccess:

AddHandler fastcgi-script .fcgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L]

Después, crea un pequeño script que le diga a Apache como iniciar tu programa FastCGI. Crea un archivo mysite.fcgi, colócalo en tu directorio Web, y asegúrate de hacerlo ejecutable:

#!/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")

20.4.5.1. Reiniciando el Server Iniciado

Si cambias cualquier código Python en tu sitio, necesitarás decirle a FastCGI que el código ha cambiado. Pero no hay necesidad de reiniciar Apache en este caso the. Sólo volver a subir mysite.fcgi — o editar el archivo — de manera que la fecha y hora del archivo cambien. Cuando Apache ve que el archivo ha sido actualizado, reiniciará tu aplicación Django por ti.

Si tienen acceso a la línea de comandos en un sistema Unix system, puedes hacer esto fácilmente usando el comando touch:

$ touch mysite.fcgi