NginxでRubyのCGIを動かす

  • 1
    いいね
  • 0
    コメント

はじめに

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;

参考記事