NginxでRubyのCGIを動かす

More than 1 year has passed since last update.


はじめに

NginxはCGIを標準では実行できませんが、FCGI Wrapを使うとCGIをFastCGIとして実行してくれます。

大昔に作ったRubyのCGIのアプリをNginxのサーバ上で動かしたかったので、FCGI Wrapを試してみました。

注意点として、FCGI WrapはFastCGIのインターフェースを提供してくれるだけなので、CGIと同様にユーザーから要求がある度に、プロセスの生成と破棄が行われるため、パフォーマンスは悪いみたいです。


環境

今回試した環境です。


  • Conoha VPS

  • Ubuntu 16.04.3 LTS (Xenial Xerus)

  • Nginx/1.10.3

  • Ruby 2.3.1p112 (2016-04-26)

タイトルにはRubyのCGIと書きましたが、設定のlocationの拡張子さえ変えれば、PerlやPythonやPHPなど他の言語でも同じように設定できると思います。


設定手順

FCGI Wrapの公式ページを参考にセットアップしました。


FCGI Wrapのインストール

sudo apt install fcgiwrap


設定


/etc/nginx/fcgiwrap.conf の作成

cp /usr/share/doc/fcgiwrap/examples/nginx.conf /etc/nginx/fcgiwrap.conf

今回はRubyのCGIを動かしたかったので、以下のように修正しました。

diff --git a/usr/share/doc/fcgiwrap/examples/nginx.conf b/etc/nginx/fcgiwrap.conf

index 5bdfdf1..e218726 100644
--- a/usr/share/doc/fcgiwrap/examples/nginx.conf
+++ b/etc/nginx/fcgiwrap.conf
@@ -1,13 +1,13 @@
# Include this file on your nginx.conf to support debian cgi-bin scripts using
# fcgiwrap
-location /cgi-bin/ {
+location ~ .rb$ {
# Disable gzip (it makes scripts feel slower since they have to complete
# before getting gzipped)
gzip off;

# Set the root to /usr/lib (inside this location this means that we are
# giving access to the files under /usr/lib/cgi-bin)
- root /usr/lib;
+ #root /usr/lib;

# Fastcgi socket
fastcgi_pass unix:/var/run/fcgiwrap.socket;
@@ -16,5 +16,5 @@ location /cgi-bin/ {
include /etc/nginx/fastcgi_params;

# Adjust non standard parameters (SCRIPT_FILENAME)
- fastcgi_param SCRIPT_FILENAME /usr/lib$fastcgi_script_name;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}


/etc/nginx/fcgiwrap.conf のインクルード

Nginxの設定ファイル構成によりますが、普通は /etc/nginx/sites-available/default の server ブロック内で読み込んでおけばいいと思います。

server {

+ # fast cgi support
+ include /etc/nginx/fcgiwrap.conf;
}


RubyのCGIスクリプト

まずは単純なスクリプトでテストしました。

適当な場所にパーミッションを正しく指定して配置してください。

#!/usr/bin/ruby

puts "Content-Type: text/html\n\n"
puts "<html>"
puts "<head><title>Test</title></head>"
puts "<body>"
puts "<h1>Hello CGI World!</h1>"
puts "</body>"
puts "</html>"


トラブルシューティング

躓いたポイントを紹介します。


SCRIPT_FILENAMEの設定

パーミッションは正しいのに403エラーとなってしまいました。

エラーログ /var/log/nginx/error.log を見ると以下のようになっていました。

2017/10/05 11:49:03 [error] 9728#9728: *45 FastCGI sent in stderr: “Cannot get script name, are DOCUMENT_ROOT and SCRIPT_NAME (or SCRIPT_FILENAME) set and is the script executable?” while reading response header from upstream, client: xxx.xxx.xxx.xxx, server: _, request: “GET /app/test.rb HTTP/1.1", upstream: “fastcgi://unix:/var/run/fcgiwrap.socket:“, host: “xxx.xxx.xxx.xxx”

これは /etc/nginx/fcgiwrap.confSCRIPT_FILENAME を修正したら動きました。

-fastcgi_param SCRIPT_FILENAME  /usr/lib$fastcgi_script_name;

+fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;


参考記事