Como usar o Django com FastCGI, SCGI ou AJP

Apesar da instalação atualmente preferida para rodar o Django ser Apache com mod_wsgi, muitas pessoas usam hospedagem compartilhada, onde protocolos como FastCGI, SCGI ou AJP são a única opção viável. Em algumas instalações, estes protocolos pode fornecer uma performance melhor que o mod_wsgi.

Note

Este documento foca primariamente no FastCGI. Outros protocolos, como SCGI e AJP, são também suportados, através do pacote do Python flup. Veja a seção Protocolos abaixo para detalhes sobre SCGI e AJP.

Essencialmente, o FastCGI é uma forma eficiente de deixar uma aplicação externa servir páginas para um servidor Web. O servidor Web deleta as requisições Web vindas (via socket) para o FastCGI, que executa o código passando a resposta de volta ao servidor Web, que, por sua vez, passa-o de volta ao navegador do cliente.

Como mod_python, o FastCGI permite que o código fique na memória, permitindo requisições serem servidas sem tempo de inicialização. Diferentemente do mod_python (ou mod_perl), um processo FastCGI não roda dentro do processo do servidor Web, mas em um processo persistente separado.

Porque rodar código em um processo separado?

A modalidade tradicional mod_* no Apache embute várias linguagens de script (mais notavelmente PHP, Python e Perl) dentro do espaço do processo de seu servidor Web. Embora isto diminua o tempo de inicialização – porque o código não tem que ser lido em disco para cada requisição – ele vem com custo de uso de memória. Para mod_python, por exemplo, todo processo Apache carrega seu próprio interpretador Python, que consome um montante considerável de RAM.

Devido a natureza do FastCGI, ainda é possível ter processos que rodem sob uma conta de usuário diferente do processo do servidor Apache. O que é um grande benefício para segurança em sistemas compartilhados, por que significa que você pode assegurar o seu código de outros usuários.

Pré-requisito: flup

Antes que você possa começar a usar o FastCGI com o Django, você precisará instalar o flup, uma biblioteca Python para lidar com FastCGI. A versão 0.5 ou as mais recentes devem funcionar muito bem.

Iniciando seu servidor FastCGI

O FastCGI opera sobre um modelo cliente-servidor, e na maioria dos casos você estará iniciando o processo FastCGI em seu próprio. Seu servidor Web (seja o Apache, lighttpd, ou qualquer outro) somente contata seu processo Django-FastCGI quando o servidor precisa que uma página dinâmica seja carregada. Porque o daemon já está rodando com o código em memoria, ele está pronto para servir uma resposta rapidamente.

Note

Se você está em sistema de hospedagem compartilhada, você provavelmente será forçado a usar o processo FastCGI gerenciado pelo servidor Web. Veja a seção abaixo, rodando o Django em processos gerenciados pelo servidor Web para mais informações.

Um servidor Web pode se conectar com um servidor FastCGI de uma das duas maneiras disponíveis: Ele pode usar cada um dos sockets de domínios Unix (um “pipe nomeado” em sistemas Win32), ou ele pode usar um socket TCP. O que você escolher é de sua preferência; um socket TCP é normalmente mais fácil devido aos problemas de permissões.

Para iniciar seu servidor, primeiro mude dentro do diretório de seu projeto (aonde quer que seu manage.py esteja), e então rode o comando runfcgi:

./manage.py runfcgi [options]

Se vocÊ especificar help como a única opção depois de runfcgi, ele irá mostrar uma lista de todas as opções disponíveis.

Você precisará especificar ainda um socket, um protocolo ou ambos host e porta. Então, quando você configurar seu servidor Web, você somente precisará apontá-lo para o host/port ou socket que você especificou quando iniciou o servidor FastCGI. Veja os Exemplos, abaixo.

Protocolos

O Django suporta todos os protocolos que o flup suporta, fastcgi, SCGI e AJP1.3 (o Apache JServ Protocol, versão 1.3). Selecione seu protocolo preferido usando a opção protocol=<protocol_name> com ./manage.py runfcgi -- onde <protocol_name> pode ser um dos: fcgi (o padrão), scgi ou ajp. Por exemplo:

./manage.py runfcgi protocol=scgi

Exemplos

Rodando um servidor em threads em uma porta TCP:

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

Rodando um servidor preforked em um socket de domínio Unix:

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

Socket security

Django's default umask requires that the webserver and the Django fastcgi process be run with the same group and user. For increased security, you can run them under the same group but as different users. If you do this, you will need to set the umask to 0002 using the umask argument to runfcgi.

Executando sem o deamonizing (rodar em background) o processo (bom para debugging):

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

Parando o daemon FastCGI

Se você tem o processo rodando em foreground, é bem fácil de pará-lo: Simplesmente pressionando Ctrl-C você parará e fechará o servidor FastCGI. Entretanto, quando você está com processos em background, você precisará recorrer ao comando kill do Unix.

Se você especificr a opção pidfile para o runfcgi, você poderá matar o daemon do processo FastCGI desta forma:

kill `cat $PIDFILE`

...onde $PIDFILE é o pidfile que você especificou.

Para facilitar o reinício do seu daemon FastCGI no Unix, tente este pequeno script shell:

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

Configuração do Apache

Para usar o Django com o Apache e FastCGI, você precisará ter o Apache instalado e configurado, com mod_fastcgi instalado e habilitado. Consulte a documentação do Apache para instruções.

Uma vez que você tenha realizado a instalação, aponte o Apache para sua instância do Django FastCGI editando o arquivo httpd.conf (configuração do Apache). Você precisará fazer duas coisas:

  • Usar a diretiva FastCGIExternalServer para especificar a localização do seu servidor FastCGI.
  • Usar mode_rewrite para apontar as URLs para o FastCGI como se deve.

Especificando a localização do servidor FastCGI

A diretiva FastCGIExternalServer diz ao Apache como encontrar seu servidor FastCGI. Como a documentação do FastCGIExternalServer explica, você pode especificar ambos socket ou um host. Aqui há alguns exemplos de ambos:

# Conecta o FastCGI via socket / pipe nomeado.
FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock

# Conecta o FastCGI via um host/port TCP.
FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033

Em ambos os casos, o arquivo /home/user/public_html/mysite.fcgi na verdade não tem de existir. Ele é somente uma URL usada pelo servidor Web internamente -- um hook para significando que as requisições para uma URL devem ser manipuladas pelo FastCGI. (Mais sobre isto na próxima seção.)

Usando o mod_rewrite para apontar URLs no FastCGI

O segundo passo é dizer ao Apache para usar o FastCGI para URLs que combinam com certos padrões. Para fazer isto, use o módulo mod_rewrite e redirecione as URLs para mysite.fcgi (ou o que você tenha especificado na diretiva FastCGIExternalServer, como explicado na seção anterior).

Neste exemplo, nós dizemos ao Apache para usar o FastCGI como manipulador de qualquer requisição que não represente um arquivo do sistema de arquivos e não com /media/. Este é provavelmente caso mais comum, se você estiver usando o admin do 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,PT]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
</VirtualHost>

O Django automaticamente usará a versão pre-rewrite da URL quando estiver construindo URLs com a tag de template {% url %} (e métodos similares).

Configuração do lighttpd

O lighttpd é um servidor Web bem leve, comumente usado para servir arquivos estáticos. Ele suporta FastCGI nativamente e, esta, é uma boa escolha para servir ambas páginas estáticas e dinâmicas, se seu site não tem qualquer necessidade especifica relacionada ao Apache.

Esteja certo que mod_fastcgi está na sua lista de módulos, em algum lugar depois de mod_rewrite e mod_access, mas não depois do mod_accesslog. Você provavelmente precisará do mod_alias, para servir as medias do admin. 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",
)

Executando múltiplos sites Django em um lighttpd

O lighttpd deixa você usar "configuração condicional" para permitir que a configuração seja customizada por host. Para especificar múltiplos sites FastCGI, é só adicionar um bloco condicional na sua configuração do FastCGI para cada site:

# Se o hostname for 'www.example1.com'...
$HTTP["host"] == "www.example1.com" {
    server.document-root = "/foo/site1"
    fastcgi.server = (
       ...
    )
    ...
}

# Se o hostname for 'www.example2.com'...
$HTTP["host"] == "www.example2.com" {
    server.document-root = "/foo/site2"
    fastcgi.server = (
       ...
    )
    ...
}

Você pode também rodar múltiplas instalações do Django no mesmo site, simplesmente especificando múltiplas entradas na diretiva fastcgi.server. Adicione um FastCGI host para cada um.

Configuração do Cherokee

O Cherokee é um servidor Web muito rápido, flexível e fácil de configurar. Ele suporta tecnologias muito difundidas hoje: FastCGI, SCGI, PHP, CGI, SSI, TLS e conexões criptografadas por SSL, Vitual hosts, Authentication, encoding em tempo de execução, Load Balancing, compatível com arquivos de log do Apache, Data Base Balancer, Reverse HTTP Proxy e muito mais.

O projeto Cherokee provê uma documentação para configurar o Django com o Cherokee.

Rodando o Django em ambiente compartilhado com Apache

Muitos hospedeiros não permitem que você rode seus próprios daemons de servidor ou editar o arquivo httpd.conf. Nestes casos, ainda é possível rodar o Django usando processos gerados pelo servidor Web.

Note

Se você está usando processos gerados pelo servidor Web, como explicado nesta seção não há necessidade de você iniciar o servidor FastCGI você mesmo. O Apache gerará um número de processos, escalando como ele precisar.

No seu diretório Web raiz, adicione isto ao arquivo chamado .htaccess:

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

Então, crie um pequeno script para dizer ao Apache como gerar seu programa FastCGI. Crie um arquivo mysite.fcgi e coloque-o no seu diretório Web, e assegure-se de torná-lo executável:

#!/usr/bin/python
import sys, os

# Adicione um caminho customizado do Python.
sys.path.insert(0, "/home/user/python")

# Mudando para o diretório do seu projeto. (Opcional.)
# os.chdir("/home/user/myproject")

# Setar a variável de ambiente DJANGO_SETTINGS_MODULE.
os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings"

from django.core.servers.fastcgi import runfastcgi
runfastcgi(method="threaded", daemonize="false")

Restartando o servidor gerado

Se você mudou qualquer código Python do seu site, você precisará dizer ao FastCGI que o código mudou. Mas não há necessidade de reiniciar o Apache neste caso. Ao invés, somente re-envie o mysite.fcgi, ou edite o arquivo, desta forma o timestamp do arquivo mudará. Quando o Apache ver que o arquivos foi atualizado, ele irá reiniciar sua aplicação Django para você.

Se você tem acesso ao terminal em um sistema Unix, você pode realizar isto facilmente usando o comando touch:

touch mysite.fcgi

Servindo arquivos de mídia da administração

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.

Forçando o prefixo de URL para um valor em particular

Como muitas destas soluções baseadas no FastCGI requerem re-escrita de URL em algum ponto dentro do servidor Web, a informação de caminho que o Django vê pode não ser a mesma da URL original que foi passada. Isto é um problema se a aplicação Django é servida sob um prefixo particular e você deseja que as URLs geradas com a tag {% url %} apareçam com o prefixo, ao invés da versão re-escrita, que pode conter por exemplo, mysite.fcgi.

O Django faz uma boa tentativa pra descobrir qual o verdadeiro nome de prefixo do script que deve ser. Em particular, se o servidor Web seta o SCRIPT_URL (específica para o mod_rewrite do Apache), ou REDIRECT_URL (setada por alguns servidores, incluindo Apache + mod_rewrite em algumas situações), o Django encontrará o prefixo original automaticamente.

Nos casos onde o Django não encontra o prefixo corretamente e onde você quer que o valor original seja usado nas URLs, você pode setar a configuração FORCE_SCRIPT_NAME no arquivo settings principal. Isto seta o nome do script uniformemente para toda URL servida via este arquivo settings. Assim, você precisará usar arquivos de configurações diferentes, se você quiser diferentes conjuntos de URLs para ter nomes de scripts diferentes neste caso, mas está é uma situação rara.

Como um exemplo de como usá-lo, se sua configuração do Django está servindo todas as URLs em '/' e você esperava usar esta configuração, você poderia setar FORCE_SCRIPT_NAME = '' no seu arquivo settings.