CentOS 6, Apache 2.2サーバーでPHP複数バージョンを使用する

isdはじめに

1つのサーバーOSで複数のWebサイトをホストしている場合、PHPの複数バージョンを使用したい(バージョンを混在させたい)、というケースがあります。

たとえば、
Webサイト1は、PHP 5.6が必要(PHP 7に非対応)
Webサイト2は、PHP 7.2が必要(PHP 5に非対応)
など。

このような場合、複数バージョンのPHPをインストールし、各バージョンごとのPHP-FPMを起動します。
そして、Apache 2.4であれば、Apacheの設定で SetHandler で mod_proxy_fcgi を使用して、ホスト名やURLパスなどの条件に応じて、各バージョンのPHP-FPMに紐づければOKです。

PHP 5.6のWebサイト向け。

<FilesMatch \.php$>
    SetHandler "proxy:fcgi://127.0.0.1:9056"
</FilesMatch>

 

PHP 7.2のWebサイト向け。

<FilesMatch \.php$>
    SetHandler "proxy:fcgi://127.0.0.1:9072"
</FilesMatch>

 

PHPの処理を、FastCGIによる外部プロセスとしてApacheから外出しすることで、複数のPHPを混在できるというわけです。

(参考)
・Yum で複数バージョンの PHP を共存させる – Qiita
https://qiita.com/bezeklik/items/860ba080bf4c664cd8e9

ところが、CentOS 6のリポジトリに含まれる Apache 2.2 の mod_proxy_fcgi は、SetHandlerに非対応なので、この方法は使えません。
また、以下のように ProxyPassMatch を使用する方法もありますが、、

    ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9072/var/www/html72/$1

 

この方法だと、「DirectoryIndex が効かない」「.htaccess でディレクトリごとの制御ができない」などの問題があります。

(参考)
・php-fpm での php 実行は SetHandler で! – あらかると
https://www.starlink.jp/php-fpm-sethandler/

この問題は、mod_proxy_fcgi の代わりに、mod_fastcgi を使用することで解決できます。

ここでは、Apache 2.2 + mod_fastcgi で、PHP複数バージョン環境を構築する手順を記載します。

isd前提条件と要件

  • サーバーはCentOS 6で、Apache 2.2、CentOSリポジトリのPHP 5.3をインストール、mod_phpで設定、PHP 5.3のWebサイトを公開済み。
  • PHP 5.3 に加えて、PHP 5.6, PHP 7.2 を追加する。
  • PHP 5.3, PHP 5.6, PHP 7.2を使用するWebサイトのホスト名は次のとおり。
    • PHP 5.3: http://php53.example.jp/
    • PHP 5.6: http://php56.example.jp/
    • PHP 7.2: http://php72.example.jp/

※HTTPS、サーバー証明書の設定はここでは割愛します。

構成イメージはこんな感じ。


 

isd設定手順

次の設定を行います。

1. リポジトリの追加
2. PHP 5.6のインストールとPHP-FPMの設定
3. PHP 7.2のインストールとPHP-FPMの設定
4. mod_fastcgiの設定
5. Apacheの設定
6. 動作確認

以下、rootユーザーもしくは、sudo権限で実行します。

1. リポジトリの追加

PHP 5.6, 7.2をインストールするため、Remiリポジトリ、EPELリポジトリを追加します。

まず、EPELリポジトリを追加します。

 # yum install epel-release

 

続いて、Remiリポジトリを追加します。

 # yum install http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

 

2. PHP 5.6のインストールとPHP-FPMの設定

2-1. PHP 5.6のインストール

Remiリポジトリより、PHP 5.6をインストールします。
PHP 5.6は、php56-php-xxx というパッケージ名で提供されています。

 # yum --enablerepo=remi info php56-php-common

--
Available Packages
Name        : php56-php-common
Arch        : x86_64
Version     : 5.6.40
Release     : 13.el6.remi
Size        : 693 k
Repo        : remi
...
--

 

まず、php-gd, php-mcryptと依存関係のある libwebp, libmcrypt をインストールします。

 # yum --enablerepo=epel install libwebp mcrypt

 

PHP 5.6をインストールします。
PHPモジュールは必要に応じて追加してください。
(僕はだいたいこんな感じです。)
PHP-FPMを使用するので、php56-php-fpm は必須です。

 # yum --enablerepo=remi install php56 \
php56-php-devel \
php56-php-common \
php56-php-recode \
php56-php-mysql \
php56-php-gd \
php56-php-xml \
php56-php-tidy \
php56-php-mbstring \
php56-php-pdo \
php56-php-cli \
php56-php-pear \
php56-php-mcrypt \
php56-php-process \
php56-php-intl \
php56-php-fpm

 

PHP 5.6のバージョンを確認します。

 # php56 --version

PHP 5.6.40 (cli) (built: Aug 28 2019 15:35:39)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

 

PHP 5.6のConfigファイルの在り処を確認します。

 # rpm -ql php56-php-common

/opt/remi/php56/root/etc/php.d
/opt/remi/php56/root/etc/php.d/20-bz2.ini
/opt/remi/php56/root/etc/php.d/20-calendar.ini
/opt/remi/php56/root/etc/php.d/20-ctype.ini
/opt/remi/php56/root/etc/php.d/20-curl.ini
/opt/remi/php56/root/etc/php.d/20-exif.ini
/opt/remi/php56/root/etc/php.d/20-fileinfo.ini
/opt/remi/php56/root/etc/php.d/20-ftp.ini
/opt/remi/php56/root/etc/php.d/20-gettext.ini
/opt/remi/php56/root/etc/php.d/20-iconv.ini
/opt/remi/php56/root/etc/php.d/20-phar.ini
/opt/remi/php56/root/etc/php.d/20-sockets.ini
/opt/remi/php56/root/etc/php.d/20-tokenizer.ini
/opt/remi/php56/root/etc/php.ini
...

 

※必要に応じて、php.ini を編集します(ここでは割愛します)。

2-2. PHP-FPMの設定

PHP-FPMのConfigファイルの在り処を確認します。

 # rpm -ql php56-php-fpm

/etc/logrotate.d/php56-php-fpm
/etc/rc.d/init.d/php56-php-fpm
/opt/remi/php56/root/etc/php-fpm.conf
/opt/remi/php56/root/etc/php-fpm.d
/opt/remi/php56/root/etc/php-fpm.d/www.conf
/opt/remi/php56/root/etc/sysconfig/php-fpm
...

 

PHP-FPMのConfigを編集します。
以下、変更点のみ記載します。
ここでは、PHP-FPMのプロセスは、1~3で動的に増減するようにします。
listenポートとして、TCP/9056 を使用するようにするのがポイントです。
(本番運用では、適宜チューニングしてください。)

 # vi /opt/remi/php56/root/etc/php-fpm.d/www.conf

pm = ondemand
pm.max_children = 3
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 2
pm.max_requests = 500

listen = 127.0.0.1:9056

 

PHP-FPMを起動します。

 # /etc/init.d/php56-php-fpm start

 # ps aux | grep php-fpm

root      1587  0.0  0.6 372796  7060 ?        Ss   16:29   0:00 php-fpm: master process (/opt/remi/php56/root/etc/php-fpm.conf)
apache    1588  0.0  0.6 372796  6140 ?        S    16:29   0:00 php-fpm: pool www

 

3. PHP 7.2のインストールとPHP-FPMの設定

3-1. PHP 7.2のインストール

Remiリポジトリより、PHP 7.2をインストールします。
PHP 7.2は、php72-php-xxx というパッケージ名で提供されています。

 # yum --enablerepo=remi info php72-php-common

--
Available Packages
Name        : php72-php-common
Arch        : x86_64
Version     : 7.2.22
Release     : 1.el6.remi
Size        : 635 k
Repo        : remi
...
--

 

PHP 7.2をインストールします。
PHPモジュールは必要に応じて追加してください。
PHP-FPMを使用するので、php72-php-fpm は必須です。

 # yum --enablerepo=remi install php72 \
php72-php-devel \
php72-php-common \
php72-php-recode \
php72-php-mysqlnd \
php72-php-gd \
php72-php-xml \
php72-php-tidy \
php72-php-mbstring \
php72-php-pdo \
php72-php-cli \
php72-php-pear \
php72-php-mcrypt \
php72-php-process \
php72-php-opcache \
php72-php-intl \
php72-php-fpm

 

PHP 7.2のバージョンを確認します。

 # php72 --version

PHP 7.2.22 (cli) (built: Aug 28 2019 08:45:19) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.22, Copyright (c) 1999-2018, by Zend Technologies

 

PHP 7.2のConfigファイルの在り処を確認します。

 # rpm -ql php72-php-common

/etc/opt/remi/php72/php.d
/etc/opt/remi/php72/php.d/20-bz2.ini
/etc/opt/remi/php72/php.d/20-calendar.ini
/etc/opt/remi/php72/php.d/20-ctype.ini
/etc/opt/remi/php72/php.d/20-curl.ini
/etc/opt/remi/php72/php.d/20-exif.ini
/etc/opt/remi/php72/php.d/20-fileinfo.ini
/etc/opt/remi/php72/php.d/20-ftp.ini
/etc/opt/remi/php72/php.d/20-gettext.ini
/etc/opt/remi/php72/php.d/20-iconv.ini
/etc/opt/remi/php72/php.d/20-phar.ini
/etc/opt/remi/php72/php.d/20-sockets.ini
/etc/opt/remi/php72/php.d/20-tokenizer.ini
/etc/opt/remi/php72/php.ini
...

 

※必要に応じて、php.ini を編集します(ここでは割愛します)。

3-2. PHP-FPMの設定

PHP-FPMのConfigファイルの在り処を確認します。

 # rpm -ql php72-php-fpm

/etc/logrotate.d/php72-php-fpm
/etc/opt/remi/php72/php-fpm.conf
/etc/opt/remi/php72/php-fpm.d
/etc/opt/remi/php72/php-fpm.d/www.conf
/etc/opt/remi/php72/sysconfig/php-fpm
/etc/rc.d/init.d/php72-php-fpm
...

 

PHP-FPMのConfigを編集します。
以下、変更点のみ記載します。
ここでは、PHP-FPMのプロセスは、1~3で動的に増減するようにします。
listenポートとして、PHP 5.6のPHP-FPMが使用する TCP/9056 とは異なる、TCP/9072 を使用するようにするのがポイントです。

 # vi /etc/opt/remi/php72/php-fpm.d/www.conf

pm = ondemand
pm.max_children = 3
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 2
pm.max_requests = 500

listen = 127.0.0.1:9056

 

PHP-FPMを起動します。

 # /etc/init.d/php72-php-fpm start

 # ps aux | grep php-fpm

root      1587  0.0  0.6 372796  7060 ?        Ss   16:29   0:00 php-fpm: master process (/opt/remi/php56/root/etc/php-fpm.conf)
apache    1588  0.0  0.6 372796  6140 ?        S    16:29   0:00 php-fpm: pool www
root      1761  0.0  0.8 506724  8524 ?        Ss   17:32   0:00 php-fpm: master process (/etc/opt/remi/php72/php-fpm.conf)
apache    1762  0.0  0.7 506724  7684 ?        S    17:32   0:00 php-fpm: pool www

 

4. mod_fastcgiの設定

mod_fastcgi をインストール、設定します。
以下がとても参考になりました。

(参考)
・FastCGI+Apache+php インストールメモ(mod_fastcgi) – SOFTELメモ
https://www.softel.co.jp/blogs/tech/archives/5195

・複数バージョンのphpをapache+mod_fastcgiで扱う – OPENFORCE
https://www.open-force.info/177/show

・apache の FastCGI(mod_fastcgi) + PHP-FPM で phpを動かしてみる (CentOS,ScientificLinux編) – レンタルサーバー・自宅サーバー設定・構築のヒント
https://server-setting.info/centos/apache-mod_fastcgi-php-fpm.html

4-1. mod_fastcgiのインストール

mod_fastcgi 以前はRepoforgeリポジトリで提供されていましたが、Repoforgeリポジトリはなくなってしまいました。
パッケージ検索サイト pkgs.org で、mod_fastcgi を検索し、Repoforge (RPMforge) x86_64のRPMをダウンロード、インストールします。

※RPMファイルが信用できない場合は、公式サイトからソースをダウンロードして、ビルド、インストールするとよいでしょう。

 # cd /usr/local/src/
 # wget http://ftp.tu-chemnitz.de/pub/linux/dag/redhat/el6/en/x86_64/rpmforge/RPMS/mod_fastcgi-2.4.6-2.el6.rf.x86_64.rpm

 # yum install mod_fastcgi-2.4.6-2.el6.rf.x86_64.rpm

 

インストールされたファイルを確認します。

 # rpm -ql mod_fastcgi

/etc/httpd/conf.d/fastcgi.conf
/usr/lib64/httpd/modules/mod_fastcgi.so
...
/var/run/mod_fastcgi

 

4-2. mod_fastcgiの設定

/etc/httpd/conf.d/fastcgi.conf で、基本設定と、PHP-FPM を外部 FastCGIサーバーとして使用するための設定を行います。

FastCgiExternalServer を使用するので、FastCgiWrapper は Offにします。
FastCgiServer は使用しないので、FastCgiConfig はコメントアウトします。

 # vi /etc/httpd/conf.d/fastcgi.conf

User apache
Group apache

LoadModule fastcgi_module modules/mod_fastcgi.so

# dir for IPC socket files
FastCgiIpcDir /var/run/mod_fastcgi

# wrap all fastcgi script calls in suexec
#FastCgiWrapper On
FastCgiWrapper Off

# global FastCgiConfig can be overridden by FastCgiServer options in vhost config
#FastCgiConfig -idle-timeout 20 -maxClassProcesses 1

 

以下を末尾に追記します。

ScriptAlias /fcgi-bin/ /var/www/fcgi-bin/

# PHP 5.6
FastCgiExternalServer /var/www/fcgi-bin/php-fpm56 -host 127.0.0.1:9056 -pass-header Authorization 
Action php-fastcgi56 /fcgi-bin/php-fpm56

# PHP 7.2
FastCgiExternalServer /var/www/fcgi-bin/php-fpm72 -host 127.0.0.1:9072 -pass-header Authorization 
Action php-fastcgi72 /fcgi-bin/php-fpm72

 

ScriptAliasで指定したディレクトリ /var/www/fcgi-bin が存在しないと動作しないので、作成します。
(/var/www/fcgi-bin/php-fpm56, /var/www/fcgi-bin/php-fpm72 は作成不要です。)

 # mkdir /var/www/fcgi-bin

 

これで、Apache のVirtualHost Configなどで、
SetHandler php-fastcgi56
を指定すると、PHP 5.6用のPHP-FPM (127.0.0.0:9056) に、
SetHandler php-fastcgi72
を指定すると、PHP 7.2用のPHP-FPM (127.0.0.0:9072) に
接続するようになります。

5. Apacheの設定

5-1. PHP 5.6 http://php56.example.jp/ 用の設定

まず、httpd.conf で、NameVirtualHost を有効にします。

 # vi /etc/httpd/conf/httpd.conf

NameVirtualHost *:80

 

VirtualHost Configを作成します。
拡張子 .php に対して、「SetHandler php-fastcgi56」を設定することで、PHP 5.6用のPHP-FPMに接続させるのがポイントです。

 # vi /etc/httpd/conf.d/vhost_php56.example.jp.conf

<VirtualHost *:80>
    DocumentRoot /var/www/html56
    ServerName php56.example.jp

    <FilesMatch ".+\.php$">
        SetHandler php-fastcgi56
    </FilesMatch>

    ErrorLog logs/php56.example.jp-error_log
    CustomLog logs/php56.example.jp-access_log combined
</VirtualHost>

 

5-2. PHP 7.2 http://php72.example.jp/ 用の設定

VirtualHost Configを作成します。
拡張子 .php に対して、「SetHandler php-fastcgi72」を設定することで、PHP 7.2用のPHP-FPMに接続させるのがポイントです。

 # vi /etc/httpd/conf.d/vhost_php72.example.jp.conf

<VirtualHost *:80>
    DocumentRoot /var/www/html72
    ServerName php72.example.jp

    <FilesMatch ".+\.php$">
        SetHandler php-fastcgi72
    </FilesMatch>

    ErrorLog logs/php72.example.jp-error_log
    CustomLog logs/php72.example.jp-access_log combined
</VirtualHost>

 

5-3. Apacheに反映

Configの文法チェックを行い、問題なければ、Apacheを再起動します。

 # /etc/init.d/httpd configtest

 # /etc/init.d/httpd restart

 

6. 動作確認

phpinfo()を実行するphpを設置してみます。

 # vi /var/www/html/info.php

<?php
phpinfo();
?>

 # mkdir /var/www/html56
 # vi /var/www/html56/info.php

<?php
phpinfo();
?>

 # mkdir /var/www/html72
 # vi /var/www/html72/info.php

<?php
phpinfo();
?>

 

PCのWebブラウザからアクセスして、PHPの情報を確認します。
「PHP Version」でPHPのバージョンが確認できます。
また、「Server API」で、PHP-FPM(FastCGI)を使用しているかどうかが確認できます。

http://php53.example.jp/info.php
にアクセス。

PHP Version 5.3.3
...
Server API:	Apache 2.0 Handler

 

http://php56.example.jp/info.php
にアクセス。

PHP Version 5.6.40
...
Server API:	FPM/FastCGI

 

http://php72.example.jp/info.php
にアクセス。

PHP Version 7.2.22
...
Server API:	FPM/FastCGI

 

確認が終わったら、セキュリティ上好ましくないため、phpinfo() のファイルを削除します。

 # rm /var/www/html/info.php \
    /var/www/html56/info.php \
    /var/www/html72/info.php

 

これで、PHP複数バージョンの環境ができました。
PHPバージョンを必要な分だけインストールして、PHP-FPMをlistenポートを変更して起動していけば、いくつでもPHPバージョンを増やせます。

isd補足

不具合

先日、この方法でPHP 5.3とPHP 7.2の複数バージョン設定を行った際、ページ遷移の際にURLパスが
http://php72.example.jp/fcgi-bin/php-fpm56/menu/
のように、fastcgi.conf の Action で定義したパスが含まれてしまい、遷移後のページが正しく表示されない現象が発生しました。

調査したところ、HTTPSからHTTP(またはその逆)に遷移する場合、このような不具合が発生することがわかりました。
いろいろ試しましたがうまく解決する方法がなく、結局、(本来はHTTPのままにしたかった)HTTPページを強制的にHTTPSにリダイレクトすることで、ページ表示が正しくなりました。

Webサイト内で、HTTPSページとHTTPページが混在するのは好ましくありませんし、レアケースかと思いますが、このような不具合がありました。
他にも、うまくいかないケースがあるかもしれません。

ひとつのVirtualHost内で複数のPHPバージョン

ひとつのVirtualHost内で、URLパスによってPHPバージョンを変更したい場合は、<Directory> もしくは .htaccess で、ディレクトリごとに制御するとよいでしょう。

デフォルトはPHP 5.3で、/php56 は PHP 5.6、/php72 は PHP 7.2 とする場合。

 # vi /etc/httpd/conf.d/vhost_php.example.jp.conf

<VirtualHost *:80>
    DocumentRoot /var/www/html
    ServerName php.example.jp

    <Directory /php56>
        <FilesMatch ".+\.php$">
            SetHandler php-fastcgi56
        </FilesMatch>
    </Directory>

    <Directory /php72>
        <FilesMatch ".+\.php$">
            SetHandler php-fastcgi72
        </FilesMatch>
    </Directory>
...

 

↑mod_phpの設定(/etc/httpd/conf.d/php.conf)が効いているので、デフォルトはPHP 5.3となります。

デフォルトはPHP 7.2で、/php53 は PHP 5.3、/php56 は PHP 5.6 とする場合。

 # vi /etc/httpd/conf.d/vhost_php.example.jp.conf

<VirtualHost *:80>
    DocumentRoot /var/www/html
    ServerName php.example.jp

    <FilesMatch ".+\.php$">
        SetHandler php-fastcgi72
    </FilesMatch>

    <Directory /php53>
        <FilesMatch ".+\.php$">
            SetHandler application/x-httpd-php
        </FilesMatch>
    </Directory>

    <Directory /php56>
        <FilesMatch ".+\.php$">
            SetHandler php-fastcgi56
        </FilesMatch>
    </Directory>
...

 

↑mod_phpの設定(/etc/httpd/conf.d/php.conf)が効いているので、「SetHandler application/x-httpd-php」で、PHP 5.3となります。

PHP 5.3もPHP-FPM化

今回記載した構築手順は、PHP 5.3のみ mod_php を使用し、PHP 5.6/7.2は mod_fastcgi + PHP-FPM という構成でした。

この構成は、サーバー全体のメモリ使用の効率がよくないと(僕は)思います。
PHPを処理したApacheの子プロセスは、メモリ使用量が増えた状態で次のリクエストを待ち受けることになります。

ですので、PHP 5.3も専用のPHP-FPMを起動して、PHPはすべて mod_fastcgi + PHP-FPM という構成にしてしまったほうがよいでしょう。
そうすれば、Apacheは静的処理、PHP-FPMは動的処理と役割分担がはっきりしますし、Apacheのメモリ使用量が少なくなります。
PHP-FPMを起動する分のメモリ使用量増がありますが、サーバー全体では、メモリ使用量が少なくなるでしょう。

構成イメージはこんな感じになります。


 

isdおわりに

CentOS 6, Apache 2.2 のサーバー環境で、PHP複数バージョンを使用するための設定手順をまとめました。

CentOS 6のサポートは、2020年11月末までですので、残り少ない期間ですが、サーバーのOSをCentOS 7または8にアップデートする前に、PHPのみバージョンアップして動作確認もしくは運用したい場合は、有効な方法だと思います。
 

Follow me!