はじめに
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_php
とmod_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)