nginx & fcgiwrap

雖然很久以前就想換到 nginx 試試看,不過直到最近這次更新才換成功,最早單純只是想要輕量一點的 HTTP server,後來則是因為和 Apache 相比,nginx 明顯開發更新比較快,最近有很多想要嘗試各種新功能都是 nginx 先做,像是 HTTP/2,還有最近這次的 brotli 支援,而以前沒辦法換過去的最主要原因,其實是 nginx 沒有 CGI 的支援,跑 MovableType 會有困難,雖然 MovableType 可以用 FastCGI,不過很難設定,我安裝過 n 次大概也只有成功過一兩次,所以其實一直都不太考慮這個選項。

不過認真研究了一下,終於發現其實可以透過 FCGI Wrap 這個工具來達成 nginx 對 CGI script 的支援,它的作法其實就是一個中間人,把 FCGI 介面轉到 CGI 介面過去,我大概設定了一下跑 MovableType 的 nginx conf 如下:

location ~ ^/path/to/mt/mt.*\.cgi {
    gzip off;
    fastcgi_index index.cgi;
    fastcgi_split_path_info ^(.+?\.cgi)(/.*)$;
    if (!-e $document_root$fastcgi_script_name) {
        return 404;
    }
    include fastcgi.conf;

    ## MT-related
    fastcgi_param PERL5LIB $document_root/mt/lib;
    fastcgi_param MT_HOME $document_root/mt/;
    fastcgi_param MT_CONFIG $document_root/mt/mt-config.cgi;

    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param PATH_TRANSLATED $fastcgi_path_info;
    fastcgi_pass unix:/var/run/fcgiwrap.sock;
}

然後主機上要開好 FCGI Wrap 的服務,我是用 ArchLinux 的 pacman 直接裝套件,然後參考官方文件,有寫說設定檔位置/usr/lib/systemd/system/fcgiwrap.socket,cat 出來就可以看到 UNIX Socket 檔案位置ListenStream=/run/fcgiwrap.sock,這個路徑的位置其實就指到上面設定最後一行的/var/run/fcgiwrap.sock/run/var/run兩邊其實有 Symbolic Link 起來,所以兩個 sock 檔案其實是同一個。

最後要說一下 conf 裡的這行:

include fastcgi.conf;

這個fastcgi.conf檔案其實是 nginx 內建好方便大家使用的,內容如下:

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  REQUEST_SCHEME     $scheme;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

可以看到其實這個檔案就是把直接走 FCGI 時會遺失的環境變數補回去用的,nginx 還提供很多這類檔案,以前都不太清楚怎麼剛裝好的 nginx 會附上一堆沒有用到的 conf 檔,直到這次才瞭解它們其實都很有用啊。