ubuntuにインストールしたnginxでCGIを動かしてみた。

ubuntuにインストールしたnginxでCGIを動かしてみました。もともとApacheで動いていたCGIスクリプトをnginxで動くようにしています。環境は以下です。作業はrootユーザーで行いました。

【環境】
ubuntu 18.04 LTS
nginx 1.16.1

まず、nginxでCGIを動かすためにはfcgiwrapが必要なのでインストールします。

fcgiwrapのインストール
# apt install fcgiwrap

パッケージのインストールができたらfcgiwrapを確認してみます。

インストールされたパッケージの確認
# dpkg -l | grep cgi

僕の環境では赤枠で囲ったパッケージがインストールされたようです。

[広告]

fcgiwrapの設定を確認します。fcgiwrapでは設定ファイルのようなものはないらしく、/etc/init.d配下にある起動スクリプトを確認します。

fcgiwrapの起動スクリプトの場所
/etc/init.d/fcgiwrap

この起動スクリプトに記載されている設定の中で確認する項目の抜粋(以下はデフォルト値)です。


 :
NAME="fcgiwrap"
 :
# FCGI_APP Variables
FCGI_CHILDREN="1"
FCGI_SOCKET="/var/run/$NAME.socket"
FCGI_USER="www-data"
FCGI_GROUP="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"
 :

最初に、

NAME=”fcgiwrap”
FCGI_SOCKET=”/var/run/$NAME.socket”

ですが、これはnginxとfcgiwrapとのデータの受け渡しの方法です。nginxでは静的コンテンツしか処理できずCGIのような動的コンテンツはfcgiwrapが行うことになるのですが、CGIへのリクエストをnginxからfcgiwrapにどのような方法で受け渡すかを設定します。受け渡しの方法にはUnixソケットを使う方法とTCP/IPを使う方法があるのですが、デフォルトの設定ではUnixソケットを使う方法となっています。一般的にnginxとfcgiwrapを動かすサーバーが同一であればUnixソケットを使ったほうが効率がよいです。ですので、FCGI_SOCKETの設定はこのまま(デフォルトのまま)とします。

実際に、/var/run配下にfcgiwrap.socketがあるかどうか確認してみると以下のようにありました(緑線の部分、ピンク色線については後述)。

次に、

FCGI_CHILDREN=”1″

ですが、これはfcgiwrapがリクエストを待つ待機プロセスの数です。fcgiwrapはこの数分のプロセスを生成(C言語でいうfork)をしていて、リクエストが連続で来た際に待ちを作らずに並列に処理を裁ける数となります。本来はリクエスト数とサーバー性能を考慮してチューニングするべきですが、ここではいったんデフォルトのままとしておきます。

続いて、

FCGI_USER=”www-data”
FCGI_GROUP=”www-data”

ですが、これはfcgiwrapを実行するユーザー、および、グループを設定します。ここにはCGIスクリプトを実行できるユーザーを設定するのですが、ubuntuでApacheを動かす際は一般的にwww-dataを使用していて、今回はApacheで動かしていたCGIスクリプトをそのまま動かす想定なのでwww-dataのままとしておきます。

最後に、

FCGI_SOCKET_OWNER=”www-data”
FCGI_SOCKET_GROUP=”www-data”

ですが、これは先ほど記載したfcgiwrap.socketの所有者、および、グループの設定です。記載がなかった場合はFCGI_USER、FCGI_GROUPと同じになると起動スクリプトのコメントには記載されていました。こちらもデフォルトのwww-dataのままとしていたのですがfcgiwrap.socketの所有者、グループはrootになっていました(fcgiwrap.socketを確認した際のピンク色の線のところ)。ここのところの差異の理由は、ちょっとわかりませんでした。所有者はrootですが、www-dataでも読み書きできる権限となっているため問題ないのかもしれません。

fcgiwrapの設定の確認はここまでです。結果的にですが、fcgiwrapの設定は何も変えずにデフォルトのままで行きます。引き続き、nginxの設定に入ります。

[広告]

nginxの設定ファイルにCGIスクリプトへのリクエストがあった場合の動きを記載します。記載する設定ファイルはnginx.conf、もしくは、conf.d配下のconfファイルです。

nginxの設定ファイルの場所
/etc/nginx/nginx.conf
/etc/nginx/conf.d 配下のconfファイル

※nginx.confがconf.d配下のconfファイルを読み込んで(includeして)います。

記載する内容は以下です。serverディレクティブの中に記載してください。


location ~* \.cgi$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.cgi)(/.+)$;
    include fastcgi_params;
    fastcgi_index index.cgi;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_intercept_errors on;
    fastcgi_pass unix:/var/run/fcgiwrap.socket;
}

この中で一番最後にあるfastcgi_passの設定が、nginxからfcgiwrapにUnixソケットを使用してデータを引き渡す、という設定になります。他の設定はパラメータファイルのインクルードとか404エラーファイルの出力などですが、細かい説明は省略します(すみません)。そのまま貼り付けてもらえれば動くはずです。。

上記を反映した僕の場合のserverディレクティブを載せておきます。

nginx.confにnginxを動かすユーザーが記載されているのですが、そのユーザーをnginxからwww-dataに変更しておきます。nginx.confの「user」という項目です。

変更前
user nginx;
 ↓
変更後
user www-data;

以上でnginxのconfファイルの修正は終了です。confファイルのテストを行います。

confファイルの確認
# nginx -t

「syntax is ok」および「test is successful」と表示されれば問題ありません。今回はfcgiwrapの設定は変えていないのでnginxの再起動のみ行います。

nginxの再起動
# systemctl restart nginx

nginxでCGIスクリプトにアクセスしてみてください。動くと思います。

ubuntuにインストールしたnginxでPHPを動かしてみた。

ubuntuにインストールしたnginxでPHPを動かしてみました。もともとApacheで動いていたPHPアプリをnginxで動くようにしています。環境とバーチャルサーバーの設定は以下です。PHPはインストール済みです。作業はrootユーザーで行いました。

【環境】
ubuntu 18.04 LTS
nginx 1.16.1
PHP 7.2.24

【バーチャルサーバーの設定】
server {
  listen 80;
  server_name www.example.com;

  location / {
    root /var/www/html/example;
  }
  :
  :
}
server {
  listen 80;
  server_name www.hogehoge.com;

  location / {
    root /var/www/html/hogehoge;
  }
  :
  :
}

バーチャルサーバーは、/etc/nginx/conf.d/default.conf に設定済みとします。default.confでなくてもconf.d配下の別のconfファイルでも可です。nginx.confがconf.d配下のconfファイルを読み込んでいます。

Apacheでは「php7_module(libphp7.2.so)」をロードしてPHPを動かしていましたが、nginxでは「php-fpm」というパッケージが必要です。まずphp-fpmがインストールされているか確認します。

インストールされているパッケージの確認
# dpkg -l | grep php

僕の環境ではそれらしきものは見つかりませんでした。調べてみると「php-fpm」というパッケージと「php7.2-fpm」というパッケージがあるらしい。PHP7.2を使用しているのでphp7.2-fpmのほうを使うことにしようと思い、パッケージを検索してみました。またパッケージ情報も確認してみました。

パッケージの検索
# apt search php7.2-fpm

パッケージ情報の確認
# apt show php7.2-fpm

※出力結果は省略。。

問題なさそうなので(あまり根拠はないのだけど大丈夫そう)、php7.2-fpmをインストールします。

php7.2-fpmのインストール
# apt install php7.2-fpm

特に問題なくインストールは完了しました。php7.2-fpmがインストールされたか確認してみます。

インストールされているパッケージの確認
# dpkg -l | grep php

赤枠で囲った部分がインストールされたphp7.2-fpmです。続いて、php7.2-fpm、および、nginxの設定に入ります。

まず、php7.2-fpmで設定するファイルは以下です。

/etc/php/7.2/fpm/pool.d/www.conf

この設定ファイルで確認する箇所は以下の3つです。

1. 起動ユーザー
2. nginxとのプロセス間通信の方法
3. プロセス数のチューニング

1.の起動ユーザーですがデフォルトでは「www-data」になっています。今回はApacheで動かしていたPHPアプリをnginxでもそのまま動かそうと思うので起動ユーザーはwww-dataのままとします。

user = www-data
group = www-data
listen.owner = www-data
listen.group = www-data
→ これらはそのまま(変更なし)

2.のnginxとのプロセス間通信の方法についてですが少し説明を入れておきます。nginxではPHPの処理をphp7.2-fpmに任せてしまっていて「〜.php」ファイルへのアクセスが来たら、php7.2-fpmに処理を引き渡せるように設定をします。処理を引き渡す方法としてプロセス間通信を行うのですがプロセス間通信の方法として以下の2つがあります。

・Unixソケットを使う方法
・TCP/IPを使う方法

nginxはWEBサーバーの機能のみを提供しPHPを実行するのに別のアプリケーションサーバーを用意する場合(WEBサーバーとアプリケーションサーバーを分離する、つまり別々のサーバーとして2台用意する場合)は、リモート接続が可能なTCP/IPを使う方法でプロセス間通信を行います。今回の僕の環境はWEBサーバーもアプリケーションサーバーも同一のサーバーなのでUnixソケットを使う方法でプロセス間通信を行うことにします(わざわざTCP/IPで通信を行う必要がないので)。デフォルトの設定では /run/php/php7.2-fpm.sock を使用します。念の為、その場所にちゃんとソケットファイルがあるかどうか確認します。このソケットファイルはphp7.2-fpmが起動しているときに作成されています。

ソケットファイルの確認
# cd /run/php
# ll

ソケットファイルが作成されているようなので、この設定もそのままとします。

listen = /run/php/php7.2-fpm.sock
→ これはそのまま(変更なし)

3.のプロセス数のチューニングですが、結論を先に言ってしまうと僕の環境ではデフォルトのままとしました。ここは各自の環境によって必要に応じて変えるべきところなので設定値の意味だけ書いておきます。

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
;pm.max_requests = 500
→ これらはそのまま(変更なし)

意味は以下です。

pm = dynamic → プロセス数を動的に制御する
pm.max_children → 子プロセスの最大数
pm.start_servers → 起動時に作成される子プロセス数
pm.min_spare_servers → 待機子プロセス数の最小値
pm.max_spare_servers → 待機子プロセス数の最大値
pm.max_requests → 再起動するまでの最大リクエスト数

pm.max_requestsはデフォルトではコメントアウトされています。「pm = dynamic」にするとApacheのPrefork MPMの動きと同じようになるようです。

ごちゃごちゃ書いたのですが、結局の所、php7.2-fpmの設定ファイルは何も変えていません(デフォルトのままです)。nginxの設定ファイルだけ修正しました。

では、nginxのどの設定ファイルを修正したかというと以下になります(バーチャルサーバーの設定がされているファイルのことです)。

/etc/nginx/conf.d/default.conf

このdefault.confに「〜.php」ファイルへのアクセスが来たらphp7.2-fpmに処理を転送する、という内容を記載します。他にもパラメータファイルのインクルードとか404エラーファイルの出力だとかあるのですが、細かい内容は省略します(ゴメンナサイ)。以下をdefault.confに貼り付けます。


    location ~* \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors on;
        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
    }

一番最後の fastcgi_pass unix:/run/php/php7.2-fpm.sock; のところがnginxからphp7.2-fpmへphp7.2-fpm.sockを通じて処理を引き渡す設定になります。

バーチャルサーバーが設定されているのでそれぞれのseverディレクティブに上記の内容を反映したものが以下です(僕が設定した内容です)。


最後に、nginxを動かすユーザーをnginxからwww-dataに変更します。修正するファイルは以下です。

/etc/nginx/nginx.conf

nginx.confに「user」があるので、そこを変更します。

変更前
user nginx;
 ↓
変更後
user www-data;

以上でnginxのコンフィグファイルの修正は終了です。コンフィグファイルのテストを行います。

コンフィグファイルの確認
# nginx -t

「syntax is ok」および「test is successful」と表示されれば問題ありません。php7.2-fpmをインストールした直後だとphp7.2-fpmが稼働しているので一度、停止させます。nginxも停止させます。

php7.2-fpmの停止
# systemctl stop php7.2-fpm

nginxの停止
# systemctl stop nginx

起動させる順番は最初にphp7.2-fpm、次にnginxとなります。

php7.2-fpmの起動
# systemctl start php7.2-fpm

nginxの起動
# systemctl start nginx

ブラウザでPHPアプリにアクセスしてみてください。設定に問題がなければ動くと思います。info.phpにアクセスするとPHPがFastCGIで動いていることを確認できます。

サーバー起動時にnginxとphp7.2-fpmを自動起動させておきたい場合は以下の設定も忘れないようにしてください。

自動起動の設定
# systemctl enable nginx
# systemctl enable php7.2-fpm

– – – –
nginxのPHPの設定については以下の書籍を参考にさせていただきました。

Apacheを使ったことがある方は問題なく読めると思います。nginxをガッツリ知りたい人向けです。企業のエンジニアで大規模コンテンツ配信を行う必要があり、その運用をやる方は納得がいく内容でしょう。ちなみに趣味程度でnginxをいじる(僕のような)人は半分程度読めば十分でした。前半だけでTLS通信で静的コンテンツ、動的コンテンツを返すWEBサーバーの構築ぐらいはできます。