前言
VPS を買った後に、リソースの利用率が少なく、友達とシェアしたくないですか?
だが、権限の設定はしっかりしていないと、友達はみんな Linux の専門家ではないので、何かやっちまったら困ります。
ここで、独断でいいと思った「バーチャルホスト」の作り方をシェアします。
本文は CentOS 7 + Nginx + PHP-FPM + MySQL をベースに語るものです。
無難なやり方
一番安全なやり方というと、もちろんユーザーごとにユーザーを作ることです。
useradd
して、ユーザーのホームフォルダの下にウェブサイトのフォルダを作るか、それとも、Nginx にアクセス権限のある /var/www/html
などの場所に集約して、setfacl
でユーザーごとにフォルダーの権限を付けます。もちろん、PHP-FPM もユーザーごとに、Socket ファイルを作ります。完璧ですね。
だが面倒くさい。デメリットもいっぱいあります。
- PHP はユーザーごとに独立なプールがあって、コンピュータリソースが無駄に使われる。
- ユーザーのホームフォルダの下にウェブサイトのフォルダを作ると、Nginx に権限渡すのが面倒くさい。(新しく作成されたファイルは ACL 権限継承されていない可能性ある)
ここで 2019 に考えた案を紹介
簡単に言えば、面倒なことを出来るだけ避けたいです。
Nginx と PHP は全員のウェブサイトフォルダーにアクセス権を与える。だが、一つのウェブサイトの PHP プロセスは別のウェブサイトフォルダーに書き込んではいけない。
Nginx と PHP は全員のウェブサイトフォルダーにアクセス権を与えるので、面倒な設定を避けるため、統一 Nginx のユーザーで動かせる。
こうやると、PHP が新しく書き込んだファイルは nginx:nginx
になり、他のユーザーが読み取れないので、そこで、他のユーザー(友達)を全部 Group:nginx に入れる。
でもでも、**全員 Group:nginx になったら、他のユーザーフォルダーにもアクセス可能になる!**これも勿論解決しなければ。
これらを踏まえて、以下の案が生まれました。
- Nginx と PHP は
User:nginx Group:nginx
で動く。 - 友達に全員独立ユーザーを発行する、ウェブサイトフォルダーはホームフォルダの下に作って、ウェブサイトフォルダーのグループ権限は nginx に変更する。
- PHP はウェブサイトごとに制限しなければならないので、そこは、
fastcgi_param PHP_ADMIN_VALUE open_basedir
(PHP の中で実行フォルダーを制限するパラメタ)を使って、Nginx から制限かける。 - ユーザーは他人のホームフォルダーをアクセスしてはいけない、でもユーザー全員 Group:nginx にいるので、ここに、ユーザーのホームフォルダ閲覧権限だけは
setfacl
を使い、User:nginx ( Group:nginx ではない )が閲覧権限持つように設定する。
つまり
友人Aのウェブサイトは /home/A/www
にあって、友人Bのウェブサイトは /home/B/www
にする。
これらのフォルダーは Group:nginx がアクセスすることが可能です、つまり、Nginx と PHP が自由に使えます。
でも、友人Aのウェブサイトをアクセスしているのに、何かの脆弱性で友人Bのウェブサイトに PHP が実行されたらやばいことになる。ここで、fastcgi_param PHP_ADMIN_VALUE open_basedir=/home/A/www
とかで制限かける。
また、友人Aと友人Bのアカウントは、PHP が新しく作ったファイルにも編集できるようにするため、Group:nginx
のユーザーになってる。でもこれじゃ、友人Bは同時に友人Aのフォルダーにも編集権限はある。
そこで、/home/A
のアクセスに User:nginx
だけ追加することで解決する。( これで、友人Bは友人Aのウェブサイトフォルダーに権限ありますが、でも /home/A/www
に入るため、まず /home/A
に入らなきゃならない、それができなくなったので、自然にその中にある www フォルダーに進まない )
つまり!(コード実現)
username=hoge ユーザー名を変数に定義する
useradd $username 新しいユーザーを作成
usermod -a -G nginx $username このユーザーを Group:nginx に追加する
su -c "mkdir /home/$username/www" $username このユーザーのウェブサイトフォルダーを作る
chgrp nginx /home/$username/www ウェブサイトフォルダーのグループ所有者を nginx にする
chmod g+rwxs /home/$username/www グループ所有者 nginx の権限を設定する
su -c 'cat /dev/zero | ssh-keygen -t ed25519 -q -N ""' $username
su -c "cp /home/$username/.ssh/id_ed25519.pub /home/$username/.ssh/authorized_keys" $username
chmod 600 /home/$username/.ssh/authorized_keys
2019 にまだパスワードログインするとかはしていないですよね? SSH Keyでログインさせよう。
setfacl -m u:nginx:rx /home/$username ホームフォルダの閲覧権限は User:nginx だけに追加する
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PHP_ADMIN_VALUE open_basedir=$document_root:/tmp;
include fastcgi_params;
} Nginx の PHP 処理する部分に fastcgi_param PHP_ADMIN_VALUE を追加する
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
; will be used.
; RPM: apache Choosed to be able to access some dir as httpd
user = nginx
; RPM: Keep a group allowed to write in log dir.
group = nginx
もちろん、PHP-FPM のユーザー設定を忘れずに( 通常は /etc/php-fpm.d/www.conf にいます )
dbpass=`pwgen -s 24 1`
echo "ランダム作成したデータベースパスワードは: $dbpass"
mysql -u root -p <<MYSQL_SCRIPT
CREATE DATABASE $username;
CREATE USER '$username'@'localhost' IDENTIFIED BY '$dbpass';
GRANT ALL PRIVILEGES ON $username.* TO '$username'@'localhost';
FLUSH PRIVILEGES;
MYSQL_SCRIPT
最後はいつも通りにユーザーごとにデータベースを作成すればいい
ドン勝!
これで、Nginx にも、PHP にも、全く工夫せずに、ユーザーの権限分離が実現した。
唐突に終わったのですが、本文に何か間違ったものがあれば、コメントで頂ければと思います。