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

CentOSにインストールしたnginxでCGIを動かしてみます。CGIはperlでサンプルプログラムを作ります。nginxでCGIを動かすにはfcgiwrapというパッケージが必要で、そのインストール作業からです。作業はrootユーザーで行います。

【環境】
・CentOS 7.9
・nginx 1.19.6
・perl 5.16.3

まず、インストールされるfcgiwrapを確認してみます。

# yum info fcgiwrap

バージョン1.1.0のものがあるようです。fcgiwrapをインストールします(インストールログの記載は省略します)。

# yum install fcgiwrap

インストールが終わった後の設定ですが /usr/share/doc/ 配下にfcgiwrapのSETUPの説明があるので、これを見てやってみます。

SETUPにはこのように書かれています。


Perform these steps after package installation:

1. Inspect the environment file /etc/sysconfig/fcgiwrap. Set fcgiwrap daemon
   parameters acording to your needs. See man fcgiwrap for details.

2. The systemd unit files provided with this package are instantiated and must
   be started by specifiying the desired web server user account. For example,
   when using nginx, the fgciwrap service is enabled then started like so:
      
      systemctl enable fcgiwrap@nginx.socket
      systemctl start fcgiwrap@nginx.socket

   Note the socket name is used here rather than the service name. There is no
   need to enable the service itself. Indeed one cannot enable the service on
   older versions of systemd. This is by design.

   See the systemd socket documentation for further details:
   https://www.freedesktop.org/software/systemd/man/systemd.socket.html

「1.」はパラメータの設定の記載です。パラメータの設定は /etc/sysconfig/fcgiwrap ファイルで行うようですがCGIを動かすだけならデフォルトのままでも大丈夫なのでそのままにします。

「2.」はfcgiwrapの起動に関する記載のようです。nginxはCGIのデータをファイルに書き込み、fcgiwrapはそのファイルを読み込むことでCGIのデータを取得します。この連携はソケットファイルで行います。nginxと連携するソケットファイルの作成はsystemctlコマンドで行い「fcgiwrap@」の後ろに起動ユーザー名を指定するようです。

とりあえず、やってみます。今回はnginxもfcgiwrapもnginxユーザーで動かします。ソケットファイルを作ります。

# systemctl start fcgiwrap@nginx.socket

SETUPでは「systemctl enable 〜」の記載もありますがCGIを動かしてみるだけなのでこれは省略します。ソケットファイルが実際に出来たか確認します。通常は /var/run 配下に出来ると思うのでそこを確認します。

/var/run 配下にfcgiwrapのディレクトリがあり、その下にnginxが所有者のソケットファイルが出来ていました。ソケットファイルが出来ているので、どうやらこれだけでfcgiwrapの準備は終わりのようです。あとはnginx側の設定です。

nginxではfcgiwrapに処理を引き渡す設定をdefault.confのserverディレクティブに記載します。default.confは /etc/nginx/conf.d 配下にあります。以下の記載をそのまま貼り付けてください。locationディレクティブに「〜.cgi」ファイルへのアクセスがあったときの処理を記載しています。太字部分がfcgiwrapのソケットファイルの指定になります。


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/fcgiwrap-nginx.sock;
}

実際のdefault.confはこのような感じです。

修正が出来たらnginxのコンフィグテストを行います。

# nginx -t

nginx.conf syntax is ok、nginx.conf test is successful、と表示されれば大丈夫です。nginx側の設定は以上です。

CGIが動くか確認するためにperlでサンプルプログラムを作ります。サンプルプログラムは以下のものです。1行目で指定しているperlの場所は環境に合わせてください。


#!/usr/bin/perl 
print "Content-Type: text/html\n\n";
print "<!DOCTYPE html>";
print "<html>";
print "<head><title>Test</title></head>";
print "<body>";
print "<h1>This is test page</h1>";
print "</body>";
print "</html>";

これをtest.cgiという名前でnginxのドキュメントルートに配置します。ドキュメントルートはdefault.confのrootディレクティブで指定しています。test.cgiには実行権限をつけてください。

ブラウザから http://nginxのIPアドレス/test.cgi でアクセスして、このような画面が表示されれば成功です。

fcgiwrapを止めるには以下のコマンドを使います。

# systemctl stop fcgiwrap@nginx.socket

これにより /var/run/fcgiwrap 配下のソケットファイルは削除されます。

ソケットファイルをnginx以外のユーザーで作成するには「fcgiwrap@」の後ろのユーザーを変えます。apacheユーザーの場合は、

# systemctl start fcgiwrap@apache.socket

となります。ソケットファイルの所有者を変える際はnginxの起動ユーザーも変更してください。nginxがソケットファイルにアクセスできないと「Permission denied」のエラーとなってしまいますので。

= = = = = = = = = =
後日談。。(追記しました)

数日後にfcgiwrapを起動してみたらエラーになりました。


# systemctl start fcgiwrap@nginx.socket
Job for fcgiwrap@nginx.socket failed. See "systemctl status fcgiwrap@nginx.socket" and "journalctl -xe" for details.

systemctl status で見てみると「Socket service fcgiwrap@nginx.service already active, refusing.」とのこと。すでに有効になっていると言っているのですがソケットファイルはありません。systemctl stop 〜 をしてソケットファイルは削除されているのですが。。

仕方がないのでOS再起動をしてからfcgiwrapを起動したらソケットファイルが出来ました。推測になりますが systemctl stop 〜 をしてソケットファイルを消してもどこかに情報が残っているようです。SETUPの説明に systemctl enable 〜 と systemctl start 〜 の2つしか書かれていないのは停止の意味がない?からなのかもしれません。ですので、fcgiwrapはずっと起動したまま(ソケットファイルは作成したらそのまま)にしておきます。また、systemctl enable 〜 も実行しておきました。

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

CentOSにインストールしたnginxでPHPを動かしてみます。PHP本体はすでにインストール済みです。nginxとPHPを連携させるにはphp-fpmというパッケージが必要で、そのインストール作業からです。作業はrootユーザーで行います。

【環境】
・CentOS 7.9
・nginx 1.19.6
・PHP 7.2.17

php-fpmをインストールします。

# yum install php-fpm

ですが、、いきなりエラーとなってしまいました。。

このように言っています。


エラー: パッケージ: php-fpm-5.4.16-48.el7.x86_64 (base)
             要求: php-common(x86-64) = 5.4.16-48.el7
            インストール: php-common-7.2.17-1.el7.remi.x86_64 (@remi-php72)
                php-common(x86-64) = 7.2.17-1.el7.remi
            利用可能: php-common-5.4.16-48.el7.x86_64 (base)
                php-common(x86-64) = 5.4.16-48.el7
 問題を回避するために --skip-broken を用いることができます。
 これらを試行できます: rpm -Va --nofiles --nodigest

意味がわからないのでphp-fpmの情報を確認してみました。

# yum info php-fpm

これを見てなんとなくわかりました。先ほどのエラーは「yum install でphp-fpmは5.4.16がインストールされるが依存関係で必要なphp-commonの5.4.16版がなく、php-commonの7.2.17版ならインストールされている」と言っていたようです。ここでPHP本体をインストールしたときのことを思い出しました。CentOS 7 の標準のリポジトリではPHP7がないのでremiリポジトリを入れていたことを。その時の記事です。

CentOS7.4にPHP7がインストールできないと思ったときの対応

これを読み返し、remiリポジトリを指定してインストールをしました。

# yum install --enablerepo=remi-php72 php-fpm

PHP本体を入れたときと同じやり方ですね。インストールログは省略しますが、これで無事にphp-fpmがインストールできました。なお、php-fpmを入れたらPHP 7.2.17だったのが、PHP 7.2.34になりました。

[広告]

ここからphp-fpmの設定に入ります。修正するファイルは /etc/php-fpm.d/www.conf です( /etc/php-fpm.conf がphp-fpm.d配下のwww.confをincludeしています)。

まず、起動ユーザーを設定します。デフォルトではapacheとなっています。nginxの起動ユーザーとあわせておく必要があります。今回はnginxもphp-fpmもapacheユーザーで動かすことにしますので、このままとします。

補足:
nginxユーザーで起動させたい場合は「apache」を「nginx」に読み替えてください。後述するnginxの起動ユーザーの設定も同様です。

■起動ユーザーの設定
user = apache
group = apache

次に、nginxとの連携方法を設定します。nginxではPHPの処理をphp-fpmに任せるようにするのですが、この連携はプロセス間通信で行います。プロセス間通信にはTCP/IPを使う方法とUnixソケットを使う方法の2つがあります。WEBサーバーの役割をnginx、アプリケーションサーバーの役割をphp-fpmが担う場合(つまりWEBサーバーとアプリケーションサーバーを分離させる場合)は、TCP/IPでプロセス間通信を行います。Unixソケットではリモート間での接続はできません。今回は1台のサーバーにnginxもphp-fpmも入れてしまっているのでUnixソケットを使う方法で連携するようにします。

Unixソケットは /var/run 配下にphp-fpm.sockファイルとして作成するようにします。修正するところはlistenパラメータです。

■プロセス間通信方法
修正前
listen = 127.0.0.1:9000
 ↓
修正後
listen = /var/run/php-fpm.sock

php-fpm.sockファイルの所有者がapacheになるように修正をします。listen.owner、listen.group、listen.modeはコメントアウトされているのでそれを外して直します。

■ソケットファイルの所有者変更
修正前
;listen.owner = nobody
;listen.group = nobody
;listen.mode = 0660
 ↓
修正後
listen.owner = apache
listen.group = apache
listen.mode = 0660

修正したwww.confはこんな感じです。左側の数字は行番号です。

修正が終わったらphp-fpmを起動します。

# systemctl start php-fpm

ソケットファイルが出来ているか確認してみます。

# ls -l /var/run/php-fpm.sock

apacheが所有者としてphp-fpm.sockが出来ています。ちなみにですが、nginxがこのソケットファイルにアクセスできない場合は当然ながらエラーになります。その際はnginxのエラーログに「Permission denied」のエラーが出力されます。

こういうエラーです。


2021/01/23 22:52:28 [crit] 1275#1275: *1 connect() to unix:/var/run/php-fpm.sock failed (13: Permission denied) while connecting to upstream, client: xxx.xxx.xxx.xxx, server: localhost, request: "GET /xxx.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php-fpm.sock:", host: "xxx.xxx.xxx.xxx"

php-fpmの修正は以上です。

[広告]

続いてnginxの設定をします。nginxの起動ユーザーをapacheに修正します。修正するファイルは /etc/nginx/nginx.conf です。

■起動ユーザーの設定
修正前
user nginx;
 ↓
修正後
user apache;

nginxからphp-fpmに処理を引き渡す設定をdefault.confのserverディレクティブに記載します。default.confは /etc/nginx/conf.d 配下にあります。以下の記載をそのまま貼り付けてください。locationディレクティブに「〜.php」ファイルへのアクセスがあったときの処理を記載しています。太字部分がphp-fpmとのプロセス間通信の設定になります。


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:/var/run/php-fpm.sock;
}

default.confはこんな感じです。

修正が出来たらnginxのコンフィグテストを行います。

# nginx -t

nginx.conf syntax is ok、nginx.conf test is successful、と表示されれば大丈夫です。

nginxも起動します。

# systemctl start nginx

nginxのドキュメントルートにinfo.phpを作成して配置します。ドキュメントルートはdefault.confのrootディレクティブで指定しています。info.phpは3行だけ記載します。

<?php
  phpinfo()
?>

ブラウザから http://nginxのIPアドレス/info.php でアクセスして、このような画面が表示されれば成功です。