こちらの記事で紹介したように、Webサーバのコンテンツを一般ユーザの領域にしている場合、PHPなどのプログラム(動的コンテンツ)でファイルを作成したりすると、apache権限で作成してしまい、一般ユーザ領域には書き込みの権限がなく、失敗します。
この場合、ディレクトリの権限を777、つまり他人でも書き込みできる権限をディレクトリに与えれば問題は解消するように見えますが、一般公開しているディレクトリを777にすることはセキュリティ上望ましくありません。
ここでは、PHP-FPMを使用した上記問題に対する解決策を示します。具体的には、apacheユーザで書き込むのではなく、一般ユーザで書き込むように設定します。
PHP-FPMとは何をするものか
PHP-FPM(PHP FastCGI Process Manager)は、FastCGIプロトコルを使用してPHPプログラムを実行するためのプロセスマネージャです。これにより、PHPのパフォーマンスが向上し、ウェブサーバーとの連携が強化されます。以下の3点が主な機能になります。
ユーザー権限の設定: PHP-FPMでは、プールごとに異なるユーザーとグループを指定できます。これにより、異なるプールで実行されるプロセスが異なる権限を持つことが可能です。
セキュリティコンテキストの変更: PHP-FPMは、setuidとsetgidの機能を使用して、プロセスのセキュリティコンテキストを変更できます。これにより、スクリプトが実行される際の権限を制御できます。
Open Basedir設定: PHP-FPMでは、open_basedirディレクティブを使用して、PHPがアクセスできるディレクトリを制限できます。これにより、悪意あるアクセスやファイルへのアクセスを防ぐことができます。
上述のとおり、PHP-FPMにより動的なコンテンツ生成が頻繁な場合でも、セキュアで効果的な運用が可能になります。
PHP-FPMのインストール
ここでは、almalinux8系の環境で実施した内容をお伝えします。結論から、apache(webサーバ)のphpモジュールをインストールすると自動で関連付けされてインストールされます。
パッケージがインストールされているかは、以下のコマンドでご確認ください。
# rpm -qa | grep php-fpm
PHP-FPMのコンフィグ(/etc/php-fpm.d/www.conf) の設定
デフォルトのwww.confファイルは編集せずに、こちらをコピーして利用者用(ここではuser001ユーザ)のコンフィグを準備します。
# cp -p /etc/php-fpm.d/www.conf /etc/php-fpm.d/user001.conf
変更場所は、下記になります。userやgroupには一般ユーザを指定します。
# diff www.conf.org user001.conf
4c4
< [www]
---
> [user001]
24c24
< user = apache
---
> user = user001
26c26
< group = apache
---
> group = user001
38c38
< listen = /run/php-fpm/www.sock
---
> listen = /run/php-fpm/user001.sock
325c325
< slowlog = /var/log/php-fpm/www-slow.log
---
> slowlog = /home/user001/php-fpm/log/www-slow.log
419c419
< php_admin_value[error_log] = /var/log/php-fpm/www-error.log
---
> php_admin_value[error_log] = /home/user001/php-fpm/log/www-error.log
432,433c432,433
< php_value[session.save_path] = /var/lib/php/session
< php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache
---
> php_value[session.save_path] = /home/user001/php-fpm/session
> php_value[soap.wsdl_cache_dir] = /home/user001/php-fpm/wsdlcache
次に、user001ユーザのhome にphp-fpm関連(/home/user001/php-fpm と log、session、wsdlcache )ディレクトリを作成し、パーミッションを770(ただしlogディレクトリだけは750。その理由はこちらを参照)、オーナーは、user001:user001にします。設定の具体的なコマンドは以下の通りです。
# mkdir /home/user001/php-fpm
# mkdir /home/user001/php-fpm/log
# mkdir /home/user001/php-fpm/session
# mkdir /home/user001/php-fpm/wsdlcache
# chmod 770 /home/user001/php-fpm
# chmod 770 /home/user001/php-fpm/session
# chmod 770 /home/user001/php-fpm/wsdlcache
# chmod 750 /home/user001/php-fpm/log
# chown -R user001:user001 /home/user001/php-fpm
最後にサービスを起動します。
# systemctl enable php-fpm.service
# systemctl start php-fpm.service
apacheのコンフィグの設定
httpd.confやssl.confなどの、一般ユーザのドキュメントディレクトリを設定している部分に下記の黄色でマーカーしている部分を追記ます。
DocumentRoot /home/www/public_html
<Directory "/home/www/public_html">
AllowOverride All
Require all granted
Options FollowSymLinks
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php-fpm/user001.sock|fcgi://localhost"
</FilesMatch>
</Directory>
追加が終わりましたら、apacheと(念のため)php-fpmのサービスを再起動して反映させます。
# systemctl restart httpd
# systemctl restart php-fpm
動作確認のチェックポイント
以下にsockファイルができているか確認する。
# ls -l /var/run/php-fpm/
合計 4
-rw-r--r-- 1 root root 6 2月 6 11:34 php-fpm.pid
srw-rw----+ 1 root root 0 2月 6 11:34 user001.sock
srw-rw----+ 1 root root 0 2月 6 11:34 www.sock
PHP-FPMのログファイルにエラーを吐いていないか確認する。利用者のプロセスがあるかを php-fpm でgrepして確認する。
# less /var/log/php-fpm/error.log
# ps -ef | grep php-fpm
root 5499 1 0 11:23 ? 00:00:00 php-fpm: master process (/etc/php-fpm.conf)
user001+ 5500 5499 0 11:23 ? 00:00:00 php-fpm: pool user001
user001+ 5501 5499 0 11:23 ? 00:00:00 php-fpm: pool user001
user001+ 5502 5499 0 11:23 ? 00:00:00 php-fpm: pool user001
user001+ 5503 5499 0 11:23 ? 00:00:00 php-fpm: pool user001
user001+ 5504 5499 0 11:23 ? 00:00:00 php-fpm: pool user001
apache 5505 5499 0 11:23 ? 00:00:00 php-fpm: pool www
apache 5506 5499 0 11:23 ? 00:00:00 php-fpm: pool www
apache 5507 5499 0 11:23 ? 00:00:00 php-fpm: pool www
apache 5508 5499 0 11:23 ? 00:00:00 php-fpm: pool www
apache 5509 5499 0 11:23 ? 00:00:00 php-fpm: pool www
apache 5579 5499 0 11:24 ? 00:00:00 php-fpm: pool www
apache 5580 5499 0 11:24 ? 00:00:00 php-fpm: pool www
root 5582 5144 0 11:25 pts/0 00:00:00 grep --color=auto php
ファイルを作成する簡単なphp(test.php)を動かして、一般ユーザ権限で作成されるか確認する。
<?php
$file_handle = fopen( "./testfile.txt", "w");
fwrite( $file_handle, "動作テスト");
fclose($file_handle);
?>
このファイルを一般ユーザの public_html 配下に配置して、ブラウザ等でhttps://hogehoge.com/test.php にアクセスしてみます。ブラウザには何も表示されないと思いますが、public_html に testfile.txt が一般ユーザ権限で出来ていればOKです。
もし何か設定が誤っていたり、標準のapacheユーザで実行された場合は、ファイルは作成されません。
php-fpmのログローテートの設定も忘れずに
忘れがちなユーザ領域のログのローテートの設定も実施しておきます。
# more /etc/logrotate.d/php-fpm
/home/user001/php-fpm/log/*log
/var/log/php-fpm/*log {
missingok
notifempty
sharedscripts
delaycompress
postrotate
/bin/kill -SIGUSR1 `cat /run/php-fpm/php-fpm.pid 2>/dev/null` 2>/dev/null || true
endscript
}
logrotateの空動作をするオプション(-d)を付けて、実際にはローテートしませんが、エラーが出ないかどうかを確認します。
# logrotate -d /etc/logrotate.d/php-fpm
phpMyAdminなどapache権限で動作するミドルウェアがある場合は要注意
phpMyAdminなどapache権限で動作するミドルウェアがなければ特に問題ございませんが、デフォルトのwww.confの中身を変更してしまうと、うまく動かないことが判明しました。
具体的には、phpMyAdminで、こちらのとおり、phpMyAdminにrootでの利用を禁止する設定をしていたにもかかわらず、rootでログイン出来てしまいました。(もっと言うと、phpMyAdminにログイン後、temp領域にアクセス権がない、といったエラーも出ていました)
調査の結果、phpMyAdminはapache権限で動作する必要があるのに対し、上記のphp-fpmの設定で一般ユーザ権限で、phpファイルを動作させる設定になっていたため、root使用禁止部分のコンフィグ(config.inc.php)も読み込まれていないようでした。(こちらも.phpファイルです…)
ですので、このケースは、/etc/php-fpm.d/www.conf はデフォルトのまま設定変更せず、user001.confといった別のファイルを必ず作成し、そちらを利用者用に設定しましょう。
今回はここまでです。最後までお読みいただきありがとうございました。