はじめに
会社のHPをWordPressで構築していますが、「最近(忘れたころに)」DB接続エラーが起きてしまって困ることがありました(サーバー: SakuraVPS/AlmaLinuxベース)。1年ぶりに接続エラーが起きると『何事だ』と焦りますよね。
お休み中で油断して自宅でまったりとしているとき(お昼寝中)に『閲覧できないんですけど...』とトラブル連絡が来てびっくり仰天、ページ閲覧不可の状態を長引かせるわけにもいかずで焦る、とイヤな感じがしますよね。
本来は DB接続エラーにつながる原因を排除していきトラブル可能性を低くしてことがが王道だと思いますが、それをしたからといってトラブルは起こるときは起こるものです。
とりあえずHP(WP)を復旧させたい、「急ぐ、どうしよう」と思うわけです。
復旧させるにはサーバーにログインしてコンソールでSUDO
でDBサービス再起動させるのが本来の手段ですが(予想外の理由でmysqlが落ちている、とりあえず起動だけさせておきたい!の前提)
自宅にいるときなどパスワード(機密情報)を入手できずであせったりしますね。しかも作業を頼めるようなLinuxに詳しい人にも連絡つかないしの状態。これから仕事場に向かわないといけないの?いつもなら職場にVPN接続してなんとかするけど今は自宅にパソコンがないようぅぅぅ(泣)
サーバーログインをしないで気軽にDBサービス再起動できたらいいな、Linuxコマンド不慣れな人へも「DB再起動ぐらい」は頼める状態にあってほしい!が切実な願いなのです。
思い
ブラウザで特定のURLをたたくだけで、DBサービス再起動させたい、つまりブラウザ経由でsystemctl restart mariadb
を実行したい。ブラウザでたたくだけだから誰でもできるよね(お休みのときは他の人に任せてゆっくりと過ごしたい)。
今回のサーバー構成
- SakuraVPS
- OS: Almalinux 8.6 (Sky Tiger)
- WEBサーバ: Apache/2.4.37 (AlmaLinux)
- PHP: PHP 8.1.6 (cli) (built: May 11 2022 01:14:18)
- DB: mysql Ver 15.1 Distrib 10.3.32-MariaDB
考慮するべき点
APACHEを通してシェルコマンドを実行することはできるのですが、そのときのシェルコマンドの実行ユーザは APACHEユーザになります。今回の場合、APACHEユーザは apache
と設定されていました。ubuntu系
OSでよく見ますがwww-data
の場合もあります。APACHEユーザは設定により異なりますので念のために事前確認しておきましょう。
ここで問題となることがあります。APACHEユーザにはROOT権限がありませんしSUDOもできません(標準ではのお話しですが)。
そのため(そのままでは)APACHEユーザではROOT権限を必要とする『システム管理』コマンドなどを実行することができません。
ではどうしましょうか?
APACHEユーザを root
にする案
APACHEの設定でAPACHEユーザに ROOTを指定する方法です。
危険すぎるので候補として考えたくもないですね。
APACHEユーザが普通にSUDOできるようにしてあげる案
visudo で設定を与える方法です。
apache ALL=(ALL:ALL) ALL
これでsudoをつけたら何でも実行できてしまいます。
root
と同じく危険すぎて候補から除外ですね。
それとsudo をすると 実行ユーザのパスワードを求められますが、apacheユーザにはパスワードがないので実行できないかもしれません(試してないからわからない)。
特定の管理CMD限定で SUDOできるようにする案
特定の管理CMD(例: systemctl ) 限定で、sudoできるようにする方法です。
apache ALL=(ALL) NOPASSWD: systemctl
NOPASSWORD
をつけているので SUDOをしたときにパスワードを求めてこないですが、WEB経由でsystemctl
を実行できてしまいます。何でもできてしまう状態からは脱しているのですが、systemctl
という強力なコマンド(システムに与える影響が広すぎるコマンド)を直接に実行できてしまうことが『気持ちわるい』です。
できればこの方法は採用したくないです。
特定のシェルスクリプト限定でSUDOできる案
apache ALL=(ALL) NOPASSWD: /home/hoge/fuga.sh
この設定をして、fuga.sh
のなかで、sudo で 管理CMDを実行する!
を書いてみたらよさそうなのかな?
それでは実験で apacheユーザになってみましょう
hoge@pc:~$ sudo su - apache --shell=/bin/bash
apache@pc:~$
apacheユーザになった状態で sudo fuga.shを実行してみます
apache@pc:~$ sudo /home/hoge/fuga.sh
でもエラーになります。/home/hoge の参照権限が apache
にはないからです。場所が悪かった。
apache
ユーザの状態から、ユーザ=hoge
として /home/hoge/fuga.sh を実行してみましょう
apache@pc:~$ sudo -u hoge /home/hoge/fuga.sh
はい。これで、/home/hoge/fuga.sh
が実行できました(Apacheユーザで SUDO が実行されました)。
apache→hoge→SUDO実行
hoge
ユーザで SUDOをすると、パスワードを求められます。
#!/bin/bash
sudo systemctl restart mariadb
WEBページ経由で fuga.shを起動しているのですが、パスワードを自動的に付与してみましょう。SUDOにオプション-S
をつけてみます。
#!/bin/bash
echo "PASSWORD" | sudo -S systemctl restart mariadb
スクリプトのなかにパスワードを書くことにためらいがあるのであれば、こうしましょう
PASSWORD
#!/bin/bash
cat /home/hoge/passCode.txt | sudo -S systemctl restart mariadb
パスワード文字列とスクリプトを分離できました。多分、気休程度ですけどこれがよさそう。
まとめ
PHPスクリプト
<?php
exec('/var/www/kick.sh'); // USER( apache )
PHPスクリプトのなかに USER=hoge
を書くことに抵抗があるので、kick.shをはさみます。kick.sh
は apacheユーザに参照権限があるところにおきましょう。
kick.sh
ここでユーザhoge
に化かします。
#!/bin/bash
sudo -u hoge /home/hoge/fuga.sh # USER = apache ⇒ hoge
fuga.sh ( 目的である systemctlを実行する )
#!/bin/bash
cat ~/passCode.txt | sudo -S systemctl restart mariadb # USER(hoge)
passCode.txt
PASSWORD
最後に
念の為にいっておきますが、WEBブラウザからApache経由でDB再起動はすこし危険です。
危険を承知のうえで「もしものときに備えたい」気持ちが強いのであれば「メリットとリスク」をよく考えてみてから採用してみてください。会社のサーバー運用体制陣充実しているのであれば本ページで説明した方法を検討する必要性は全くありませんからね。
ブラウザでたたくURLは特定の人だけで共有するべきです。社内の誰でも勝手にいつでもDB再起動ができる状態というのは「ゼッタイニダメ」です。社外に公開するのは論外です。
キャッシュされたURLで「間違えてたたいた」も回避したいですね。
例えば、GETパラメータで 現在「日時分」を与えて、「現在日時分」でないときは無視するように、PHPスクリプトを工夫したらよいでしょう。
<?php
$params = $_GET['code']; // 2404211320 が入っている
if( isset($params) ) {
if( $params == date('ymdHi') ) {
exec("/var/www/kick.sh");
}
}