CakePHP3アプリをFastCGI方式で動かすための環境構築と設定

投稿者: | 2018年2月18日

はじめに

FastCGI方式でCakePHP3アプリを動かすための設定をまとめます。

概要

CakePHP3は初期状態で、Apache httpd 2.4のmod_phpで動かすように設定されています。

この状態からFastCGI方式で動かすためには、Apache httpd 2.4の設定以外に、CakePHP3アプリの設定も変更が必要です。

FastCGIについては「[メモ] CGIとFastCGIの仕様について」にメモしています。

検証環境

CentOS7、SCL(Software Collections)リポジトリからのLAMP環境構築について(後編)」で作成した環境をベースにします。

ホスト環境

  • macOS 10.12.6 Sierra
  • Vagrant 2.0.1
  • VirtualBox 5.2.6r120293

ゲスト環境(仮想マシン)

  • CentOS 7.4.1801 (CentOSが公式で維持、管理しているBOXイメージ)

FastCGI環境の構築

PHP拡張のインストール

php-fpmはPHPでのFastCGIの実装

[vagrant@app ~]$ sudo yum install -q -y rh-php71-php-fpm
[vagrant@app ~]$ sudo yum list -q rh-php71-php-fpm
Installed Packages
rh-php71-php-fpm.x86_64               7.1.8-1.el7                @centos-sclo-rh

サービスの自動起動設定

[vagrant@app ~]$ sudo systemctl enable -q rh-php71-php-fpm
## サービス起動
[vagrant@app cms]$ sudo systemctl start rh-php71-php-fpm

Apache httpdで必要なモジュールを確認

[vagrant@app ~]$ httpd -M | grep -F -e "proxy_module" -e "proxy_fcgi_module"
 proxy_module (shared)
 proxy_fcgi_module (shared)

mod_phpとmod_cgiの無効化

FastCGIだけが有効な環境とするため、他のCGIライブラリを読み込まないようにします。

[vagrant@www ~]$ cd /opt/rh/httpd24/root/etc/httpd/conf.modules.d

## 無効化前
[vagrant@www conf.modules.d]$ httpd -M | egrep -e "\s(cgi_module|php7_module)"
 cgi_module (shared)
 php7_module (shared)

## 無効化(コメントアウト)
[vagrant@www conf.modules.d]$ sudo bash -c 'sed -i -e "s/^/###/g" 01-cgi.conf'
[vagrant@www conf.modules.d]$ sudo bash -c 'sed -i -e "s/^/###/g" 15-rh-php71-php.conf'
[vagrant@www conf.modules.d]$ sudo systemctl restart httpd24-httpd

## 無効化後
[vagrant@www conf.modules.d]$ httpd -M | egrep -e "\s(cgi_module|php7_module)"
[vagrant@www conf.modules.d]$

Apache httpdの設定

mod_phpのために追加したVirtualHostの設定は削除(もしくはコメントアウト)します。

/opt/rh/httpd24/root/etc/httpd/conf/httpd.confの末尾に以下の設定を追加します。

...省略

<VirtualHost *:80>
  DocumentRoot /srv/www/app/cms/webroot
  ServerName www.local

  DirectoryIndex disabled

  <Directory /srv/www/app/cms/webroot>
    AllowOverride none
    Options FollowSymLinks
    Require all granted

    RewriteEngine On
    RewriteRule ^favicon.ico$ - [L]

    RewriteCond %{REQUEST_FILENAME} -f
    RewriteRule ^(css|font|img|js)/.+$ - [L]

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule (.*) fcgi://127.0.0.1:9000/srv/www/app/cms/webroot/index.php/$1 [L,P]
    
    RewriteRule ^ - [L,R=404]
  </Directory>
</VirtualHost>

CakePHPの設定

.htaccessファイルによるRewriteを行わない場合、CakePHPの設定を変更しないとHtmlヘルパーで生成するURLにコントローラー名が余分に付き、cssやimgなどが読み込めず崩れた画面になります。

変更は以下の2ヶ所です。

...省略
    'App' => [
        'namespace' => 'App',
        'encoding' => env('APP_ENCODING', 'UTF-8'),
        'defaultLocale' => env('APP_DEFAULT_LOCALE', 'en_US'),
        'base' => '',                      // <= 変更点(1)  falseを''に変更する	
        'dir' => 'src',
        'webroot' => 'webroot',
        'wwwRoot' => WWW_ROOT,
        'baseUrl' => env('SCRIPT_NAME'),   // <= 変更点(2)  コメントアウトを解除する
        'fullBaseUrl' => false,
        'imageBaseUrl' => 'img/',
        'cssBaseUrl' => 'css/',
...省略

Apache httpdの設定内容の説明

Apache httpdの設定について説明します。

不要なモジュールについて

不要なモジュールは読み込まないのが良い方法ですが、開発環境として色々試すため、不要な機能は無効化で対応します。例外として、mod_phpmod_cgiは動作確認の妨げになるので読み込まないようにしています。

DirectoryIndexの無効化

CakePHP3ではDocumentRootにあるindex.phpが全ての起点になります。リクエストのURLにはindex.phpを含まず、Rewrite(同等の置き換え)によりindex.phpへのアクセスに変換します。なので、DirectoryIndexディレクティブによる処理が邪魔になるので無効(disabled)にします。

DirectoryIndex disabled

RewriteEngineの有効化

FastCGIを利用する場合、Apache httpdはリバースプロキシとして動作し、FastCGIサーバーへCGIリクエストを送ります。Apache httpdでリバースプロキシとして処理を行う複数の方法がありますが、ここではRewriteEngineを利用します。

CakePHP3アプリの動的な部分はFastCGIで処理しますが、フォントや画像などの静的なファイルは、Apache httpdで処理して返します。振り分けルール(RewriteRule)と条件(RewriteCond)の記述が容易なのがRewriteEngineを利用する理由です。

Options FollowSymLinks
RewriteEngine On

シンボリックリンクが無効化されていると、同類の処理ができるRewriteRuleがOnに出来ないためFollowSymLinksを指定しています。

RewriteRuleについて

CakePHP3アプリのDocumentRootは以下のようになっています。

/srv/www/app/cms/webroot
├── css         # <= スタイルシート
│   ├── base.css
│   ├── cake.css
│   └── home.css
│
├── font         # <= フォントデータ
│   ├── cakedingbats-webfont.eot
│   ├── cakedingbats-webfont.svg
│   ├── cakedingbats-webfont.ttf
│   ├── cakedingbats-webfont.woff
│   └── cakedingbats-webfont.woff2
│
├── js          # <= Javascript
│
├── img          # <= 画像データ
│   ├── cake.icon.png
│   ├── cake-logo.png
│   ├── cake.logo.svg
│   └── cake.power.gif
│
├── favicon.ico  # <= ファビコン
└── index.php    # <= CakePHP3の起点

振り分けルール(RewriteRule)と条件(RewriteCond)を決める方針として、動的に処理するのはCakePHP3のindex.phpのみとし、静的ファイルは出来るだけ狭い範囲で許可します。

(この設定は過去の脆弱性を調べて研究中なので、まだまだユルユルです)

favicon(ファビコン)に対応

ファビコンの画像ファイルは、DocumentRootにfavicon.icoとして配置されています。

ファイル名の完全な一致を条件とします。

RewriteRule ^favicon.ico$ - [L]

スタイルシート、フォント、画像、Javascriptへの対応

それぞれのディレクトリ以下で実在するファイルなら処理します。

RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(css|font|img|js)/.+$ - [L]

CakePHP3アプリへのリクエストに対応

CakePHP3の基本のリクエストは<scheme>://<ホスト>/<コントローラ名>/<アクション名>/<パラメータ>です。index.phpに<コントローラ名>/<アクション名>/<パラメータ>が情報として渡され、ルーティングによりコントローラのアクションが呼び出されます。

コントローラなどのファイルはDocumentRoot外に配置されているので、Webサーバーからは実在しないファイルへのリクエストとなります。なので、存在しないファイルを条件としています。

RewriteRuleで呼び出す場合、schemeにはfcgiを指定しフラグとしてPを付けます。pフラグを付けることでプロキシとしての処理が行われます。

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) fcgi://127.0.0.1:9000/srv/www/app/cms/webroot/index.php/$1 [L,P]

あるはずの無い静的ファイルへのリクエストに対応

ここまでで、許可していない静的ファイルへのリクエストだけが残ります。仮の処置で404 Not Foundで返します。(不正に作成されない限り許可していない静的ファイルは存在しません)

RewriteRule ^ - [L,R=404]

まとめ

構築と破壊を繰り返すこと十数回、やっとLAMP環境の構成要素と、必要な工数が把握できました。

FastCGI方式での実行も、まだ、Apache httpdをプロセスベース(prefork)で実行しているため本来のパフォーマンスアップになっていません。ここからパフォーマンスチューニングの感覚と、httpd.confの設定と読み込むモジュールの整理を行いセキュリティの強化を検証していきます。

ソフトウェアコレクション(SCL)について

今回、ソフトウェアコレクション(SCL)のみでLAMP環境を構築してきましたが、

  • 設定ファイルやログファイルがSCL独自のルールで配置される
    構築や運用・監視にSCL専用の資料が必要となる。
    (Filesystem Hierarchy Standardのルールから外れている)
  • 資料が少ない
    本家 Red Hat Software Collectionsは、公式サイトで資料を公開しているが肝心な所がサブスクリプション契約者のみしか見れない。

などの理由からCentOSで、本番環境に利用するのは難しいという感想です。何回も作ったので開発環境はチャチャっと作れるのだけどなぁノωT)