NginxでCGIを動かそうと頑張った話

  • 15
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

この記事はnginxアドベントカレンダーの20日の記事です。

Nginx、いいですよね。速くて設定も楽で。
でもCGI使えません。今時CGIなんて使ってんじゃねーよ!という声もごもっともなのですが、用途が極めてニッチなアプリケーションの中には、未だにCGIのものも少なくないのです。その大きな大きな理由が、 Apacheで動いている旧態依然としたレンタルサーバ向けの用途を念頭に置いている というものです。

Why CGI

CGIが、FCGIやWSGI等の新しい技術と比較して段違いに優位な点は、FTPでレンタルサーバの然るべき場所に然るべきパーミッションで設置するだけで使えるところです。これは比較的ネットワーク関連の知識がなくても、身内だけで該当ツールを用いて遊べればそれでいい、という人に対しては、敷居を下げる点で優位に働きます。
一方で、SSHも叩けない軟弱なサーバへの設置を良しとしない私のような偏屈な人に対しては、敷居を下げたはずのCGIが設置の足枷になってしまいます。何せnginx単体で設置ができないのですから。

fcgiwrap

そこでnginxと協力して、完全にCGIとして書かれたプログラムをFCGIにラップしてくれるプログラム、fcgiwarpを使って、CGIを動かしてみる事にします。
素直にApache使えよ、という言葉は聞こえない

以下の作業はDebian jessieおよびnginx1.9.9でテスト済みです。

【注意】 FCGIにラップする ≠ FCGIの性能が出る

fcgiwrapは、あくまでFCGIのインターフェイスを提供してくれるだけで、裏ではforkしてCGIプログラムを実行しています。
100%FCGIで書かれたアプリケーションのパフォーマンスには遠く及びません。あくまでnginxの裏で動かせるようになるだけです。

インストール

Nginx1.9.9は、公式サイトのmainlineリポジトリから取得しておきます。
Debian jessieにおいては、fcgiwrapはdebパッケージが提供されているので、 apt-get install fcgiwrap するだけで入ってくれます。

nginxの設定

全ての .cgi 拡張子を持つファイルをCGIとして実行する設定が以下になります。

location ~ \.cgi$ {
    root /path/to/root;
    fastcgi_pass unix:/var/run/fcgiwrap.socket;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

これだけでOKです。PHPをPHP-FPMで動かす設定とあまり変わりませんね。違いはfastcgi_passの部分だけです。
fastcgi_passに指定している/var/run/fcgiwrap.socketですが、これはdebパッケージからfcgiwrapをインストールすると勝手に作成されています。

fcgiwarpの設定

fcgiwrapの設定は、initスクリプトを直接編集しなければなりません。
インストールしたての状態では、以下のような記述になっています。

/etc/init.d/fcgiwrap(抜粋)
# FCGI_APP Variables
FCGI_CHILDREN="1"
FCGI_SOCKET="/var/run/$NAME.socket"
FCGI_USER="www-data"
FCGI_USER="www-data"
# Socket owner/group (will default to FCGI_USER/FCGI_GROUP if not defined)
FCGI_SOCKET_OWNER="www-data"
FCGI_SOCKET_GROUP="www-data"

このうち変更しなければならないのは、 FCGI_SOCKET 以外の全てです。

FCGI_CHILDREN

リクエストを待つワーカーの数です。 このワーカー1つごとにCGIをforkして実行する ため、nginxのワーカー数と同じようにCPU数と同じにすれば良いという訳にはいきません。適切な値はサーバや実行するアプリケーションごとに違うはずなので、見極める必要があります。

FCGI_USER、FCGI_USER

CGIを実行するユーザ・グループ名です。これが適切に設定されていないとパーミッションのエラーが起きて4xx系のエラーになります。
デフォルトはwww-dataで、これはDebianのリポジトリからnginxをインストールした場合は変える必要がないのですが、今回は公式リポジトリから最新のnginxインストールしたため、「nginx」ユーザに変える必要があります。

FCGI_SOCKET_OWNER、FCGI_SOCKET_GROUP

/var/run/fcgiwrap.socket の持ち主になります。上記の通りwww-dataユーザは今回いないので書き換える必要がありますが、コメントアウトに書いてあるとおり設定しなければFCGI_USER、FCGI_USERと同じになるので、いちいち書き換えるのが面倒ならばこの2行はコメントアウトしても良いと思います。

全て設定が終わったら、 sudo systemctl restart fcgiwrap で再起動してあげましょう。

テストしてみる

nginxの方で設定したrootのディレクトリに適当なCGIスクリプトを 実行権限をつけて 置いてアクセスし、ちゃんと実行結果が表示されれば成功です。
私は実行権限をつけるのを忘れて5分くらいハマりました。

index.cgi
#!/usr/bin/perl

print "Content-Type: text/html\n\n";
print "<html>";
print "<head><title>Test</title></head>";
print "<body>";
print "<h1>Hello CGI World!</h1>";
print "</body>";
print "</html>";
この投稿は nginx Advent Calendar 201520日目の記事です。