FastCGI, SCGI, AJP で Django を使う

revision-up-to:17812 (1.4)

Django を動作させるプラットフォームとして現在推奨しているのは WSGI ですが、多くの 人々が使っている共有ホスティングサービスには、 FastCGI や SCGI, AJP といっ たプロトコルしか選択肢がありません。

Note

このドキュメントでは、 FastCGI に重点をおいて説明しています。 SCGI や AJP といったプロトコルも、Python パッケージ flup 経由でサポートして います。 SCGI や AJP 固有の設定は、後述の 「 プロトコル 」の節を参照し てください。

FastCGI は、いわば外部アプリケーションによって Web サーバにページを提供させ る方法の一つです。Web サーバは (socket を介して) 受け取った Web リクエスト の処理を FastCGI に肩代りさせます。 FastCGI はコードを実行して、その応答を Web サーバに返します。 Web サーバはその内容をクライアントのWeb ブラウザに返 すというわけです。

WSGI と同様、 FastCGI はコードをメモリ上に残すので、リクエストはスクリプトの起 動時間を伴わずに処理されます。 ただし、例えば mod_wsgi が Apache Web サーバプロセスの 中に組み込まれるか、別のデーモンプロセスとして実行されるかを設定できるのに対 し、 FastCGI プロセスは Web サーバプロセスの中ではなく、別の永続的プロセスの中 で実行されます。

なぜ別のプロセスでコードを実行するのですか?

Apache における伝統的な mod_* の構成では、 Web サーバのプロセス空間 内に様々なスクリプト言語 (有名なのは PHP, Python, Perl です) を埋め込ん で実行します。この構成は、リクエストのたびにプログラムコードをディスク から読み出さなくてもよくなるため、起動時間を減らせるという利点がありま す — その反面、メモリの消費は莫大になります。

FastCGI の性質上、Web サーバプロセスと別のユーザアカウントでプロセスを 実行できます。この特徴は、自分のコードを他のユーザから守れるという点で、 共有ホストにおいてセキュリティ上の利点になります。

必要なもの: flup

Django で FastCGI を使うには、まず flup をインストールせねばなりません。 flup は FastCGI を使えるようにするための Python ライブラリです。 Django は バージョン0.5 以降の flup で動作します。

FastCGI サーバを起動する

FastCGI はクライアントサーバモデルで動作します。ほとんどの場合、 FastCGI プ ロセスを自分で起動することになるでしょう。 Web サーバ (Apache、 lighttpd な ど) が Djagno の FastCGI プロセスにアクセスするのは、サーバが動的ページをロー ドするときだけです。デーモンは常にコードをメモリ上にロードしたまま動作して いるので、非常に高速に応答を返せるのです。

Note

共有ホスティングサービスを使っているなら、Web サーバで管理された FastCGI プロセスを使わざるを得ないかもしれません。 Django を Web サーバ で管理された FastCGI プロセスで使うには、後に出て来る節の説明を参照して ください。

Web サーバが FastCGI サーバにアクセスするには二つの方法があります。一つは Unix ドメインソケット (Win32 システムにおける「名前付きパイプ」) で、もう一 つは TCP ソケットです。どちらを選ぶかは好みの問題です。パーミッションの問題 から、通常は TCP ソケットの方が簡単です。

サーバを起動するには、プロジェクトのあるディレクトリ (manage.py のある 場所) に移動して、 manage.pyrunfcgi コマンドを実行します:

./manage.py runfcgi [options]

runfcgihelp オプションだけを指定すると、利用可能な全ての オプションを表示します。

引数として、 socket, protocol, または、 host および port を指定せねばなりません。さらに、 Web サーバをセットアップする際に、FastCGI サーバを起動するときに使ったソケット 名か、ホスト/ポート番号の組合せを指定せねばなりません。後述の 実行例 を参照 してください。

プロトコル

Django は flup のサポートしている全てのプロトコル、すなわち fastcgi, SCGI, AJP1.3 (Apache JServ プロトコルバージョン 1.3) をサポートしていま す。使いたいプロトコルを指定するには、 protocol=./manage.py runfcgi のオプションに指定します。 <protocol_name>fcgi (デフォルト)、 scgi または ajp のいずれかです。例を以下に 示します:

./manage.py runfcgi protocol=scgi

実行例

TCP ポートを使い、スレッドモードでサーバを起動する場合:

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

Unix ドメインソケットを使い、 prefork モードでサーバを起動する場合:

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

ソケットのセキュリティ

Django のデフォルトの umask では Web サーバと Django の fastcgi が同じグ ループ かつ 同じユーザで実行されることが必要です。セキュリティを強固に するには同じグループの別のユーザで実行させることができます。こうする場合は runfcgiumask 引数を使って umask に 0002 をセットします。

デーモン化 (バックグラウンド化) させずにプロセスを起動する場合 (デバッグ時 に便利です):

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

FastCGI デーモンを止める

フォアグラウンドでプロセスを走らせているのなら、止めるのは簡単で、 Ctrl-C を押して FastCGI サーバを止めるだけですみます。バックグラウンド プロセスを使っているのなら、 Unix の kill コマンドを使わねばなりません。

pidfile オプションを指定して runfcgi を起動しているの なら、以下のようにして起動中の FastCGI デーモンを殺せます:

kill `cat $PIDFILE`

$PIDFILE は起動時に指定した pidfile の値です。

Unix 上で FastCGI デーモンを簡単に再起動させたいなら、以下のようなシェルス クリプトを試してみましょう:

#!/bin/bash

# 以下の 3 つの設定は自分の環境に合わせて置き換える
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 の設定

Django を Apache と FastCGI の構成で使うには、 Apache をインストールし、さ らに mod_fastcgi をインストールして有効にせねばなりません。詳しい手順は Apache のドキュメントを参照してください。

mod_fastcgi の構成が終ったら、 httpd.conf ファイルを編集して、 Apache に Django の FastCGI インスタンスを教えます。以下の二つの設定を行わねばなり ません:

  • FastCGIExternalServer ディレクティブを使って、 FastCGI サーバの場 所を指定します。
  • mod_rewrite を使って、リクエストが適切な FastCGI に向くようにしま す。

FastCGI サーバの場所を指定する

FastCGIExternalServer ディレクティブは、 Apache に FastCGI サーバの探し 方を教えます。 FastCGIExternalServer のドキュメント にもある通り、 socket または host のいずれかを指定せねばなりません。それぞれの例を 以下に示します:

# ソケットや名前付きパイプを経由して FastCGI に接続する場合
FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock

# TCP でホスト名とポート番号を指定して接続する場合
FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033

いずれのケースでも、 /home/user/public_html/mysite.fcgi は実際に存在し なくてもかまいません。このパスは Web サーバが内部的に使う URL に過ぎず、 FastCGI で処理すべきリクエストを URL で区別するための単なるフックです。(次 節で詳しく説明します)

mod_rewrite を使って URL が FastCGI を指すようにする

第二ステップでは、特定のパターンに一致する URL では FastCGI を使うよう Apache に指示します。前節で述べたように、 mod_rewrite モジュールを使って、 URL を mysite.fcgi (または FastCGIExternalServer ディレクティブに指 定した名前) に書き換えます。

下記の例では、ファイルシステム上に存在せず、かつパスが /media/ で始まら ないファイルに対するリクエストに対して FastCGI を使うよう Apache に指示して います。Django の admin サイトを使っているなら、これはよくある状況でしょう:

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

Django は、 {% url %} テンプレートタグ (や、同様のメソッド) で URL を構築する際、自動的にリライト前の URL を使います。

mod_fastcgi の代わりに mod_fcgid を使う

FastCGI 経由でアプリケーションを提供する別の方法が、 Apache の mod_fcgid モ ジュールを使うことです。 mod_fastcgi と比べると、 mod_fcgid の FastCGI アプリ ケーションの扱い方は、ワーカープロセスを自分自身で生成し、 FastCGIExternalServer のような何かを提供するのではないところが異なります。 このため設定が少し違った外見になります。

実際には、後ほど 共有ホスティング環境 での Django の動作について説明するのと同じように、スクリプトハンドラを追加すること になります。もっと詳しく知るには、どうぞ mod_fcgid リファレンス を参照して ください。

lighttpd での FastCGI 構成

lighttpd は静的ファイルのサービスによく使われている軽量な Web サーバです。 lighttpd はネイティブの FastCGI サポートを持っているので、 Apache の縛りが なくて、動的ページと静的ページの両方をサービスしたい場合には良い選択肢とい えます。

mod_fastcgi がモジュールリストに入っているか確かめてください。このとき、 mod_rewritemod_access よりも後ろにして、 mod_accesslog より も前にします。 admin メディアファイルを提供するなら、 mod_alias も必要 になるでしょう。

lighttpd 設定ファイルに以下の設定を追加してください:

server.document-root = "/home/user/public_html"
fastcgi.server = (
    "/mysite.fcgi" => (
        "main" => (
            # TCP で fastcgi に接続する場合は host / port を指定する
            # "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",
)

lighttpd を使って複数の Django サイトを駆動する

lighttpd には、ホストごとに設定をカスタマイズするための「条件付き設定 (conditional configuration)」があります。複数の FastCGI サイトを指定するに は、各サイトごとに FastCGI 設定を条件分岐のブロックにします:

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

fastcgi.server ディレクティブに複数のエントリを追加すれば、複数の Django を同じサイトでも駆動できます。各エントリごとに FastCGI ホストを追加 してください。

Cherokee を使う場合

Cherokee はとても高速で柔軟性があり、簡単に設定できる Web サーバです。 Cherokee は、FastCGI, SCGI, PHP, CGI, SSI, TLS や SSL による暗号化、バーチャ ルホスト、認証、動的エンコーディング、ロードバランシング、Apache 互換のログ ファイル、データベースのバランサ、リバース HTTP プロキシなどなど、最近の Webサーバがサポートしている様々な技術をサポートしています。

Cherokee プロジェクトのページには、 Cherokee で Django を運用する ための ドキュメントがあります。

Apache を使っている共有ホスティングプロバイダ上で Django を使う

共有ホスティングプロバイダの多くでは、独自のサーバデーモンを起動できなかっ たり、 httpd.conf ファイルを編集できなかったりします。このような場合で も、サーバ起動プロセスを使えば Django を駆動できます。

Note

この章で説明するような方法で Web サーバ起動プロセスを使う場合、 FastCGI サーバを自分で起動する必要はありません。Apache が必要に応じて複数のプロ セスを起動してくれます。

Web コンテンツのルートディレクトリ下に、以下のような内容のファイルを .htaccess という名前で保存します:

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

次に、 Apache に FastCGI プログラムの起動方法を教える小さなスクリプトを作成 します。 mysite.fcgi というファイルを作成して Web コンテンツディレクト リに置き、実行可能にします:

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

# Python のモジュール検索パスをカスタマイズする
sys.path.insert(0, "/home/user/python")

# カレントディレクトリをプロジェクトのディレクトリに移す (必要なら)
# os.chdir("/home/user/myproject")

# 環境変数 DJANGO_SETTINGS_MODULE を設定する
os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings"

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

これはサーバが mod_fastcgi を使っている場合に動作します。一方、 mod_fcgid を 使っている場合、 .htaccess ファイルでの少しの変更を除けば、セットアップは ほとんど同じです。 fastcgi-script ハンドラを追加する代わりに、 fcgi-handler を 追加する必要があります:

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

起動中のサーバを再起動する

サイトを構成する Python コードを変更した場合、 FastCGI にコードが変更された ことを教えねばなりません。しかし、 FastCGI の場合には Apache を再起動する必 要はありません。その代わり、 mysite.fcgi を再度アップロードするか、ファ イルを編集して、タイムスタンプを更新してください。 Apache は、ファイルのタ イムスタンプが更新されていることを発見すると、Django アプリケーションを再起 動してくれます。

Unix システムでコマンドラインシェルへのアクセスが許されているなら、 touch コマンドを使えば簡単にタイムスタンプを更新できます:

touch mysite.fcgi

Admin メディアファイルの提供

サーバやその設定がどうあれ、何らかの形で admin メディアファイルを提供する方 法を考えておかねばなりません。 modwsgi のドキュメントには、上記の構成でも使えるアドバイスがあります。

URL のプレフィクス部分を特定の値にする

FastCGI を使った設置方法は、ほとんどが URL をリライトしてウェブサーバ内部の 別の場所を指すようにしています。このとき、 Django から見えるパス情報には、 もともとの URL が反映されません。そのため、 Django アプリケーションを特定の プレフィクスの下で動かしていて、 {% url %} タグで表示される URL を、 mysite.fcgi のようなリライト後のものでなく、プレフィクスのついた URL にしたいときに問題が生じます。

Django は実際のスクリプト名プレフィクスが何だったかをそれなりにうまく調べよ うとします。特に、ウェブサーバが SCRIPT_URL を設定する場合(Apache の modo_rewrite 特有の機能です) や、 REDIRECT_URL を設定する場合 (Apache と mod_rewrite をある構成で使ったとき) には、もとのプレフィクスを自動的に 見つけ出します。

Django がプレフィクスを正しく見付けられない場合や、リライト前の値を URL に 使いたい場合には、設定ファイル中で FORCE_SCRIPT_NAME を設定して ください。この変数には、全ての URL に共通なスクリプト名を指定します。したがっ て、別々のスクリプト名を持った URL に対応するには個別に設定ファイルを用意せ ねばなりませんが、そのようなケースは稀でしょう。

例えば、全てのコンテンツを '/' 以下の URL で提供するように Django を構 成しているなら、設定ファイルには FORCE_SCRIPT_NAME = '' と指定してくだ さい。