WEBデザイナさんたちのために、
rsyncで開発サーバから本番サーバへ一発送信のスクリプトファイルを書いたのだけど、
「黒い画面(コンソールのことか…)はこわい」とおっしゃるので
一枚物のWEB画面をPHPで書いて、
そこにボタンを置いてキックする形にしようとして書いたんだけど
sudoが通らなくてはまっちまって1日無駄にした挙句
他の人の手も煩わせたのでメモしとく。
っていうか日本語の記述なかった。
参考:http://stackoverflow.com/questions/19608431/php-fpm-d-with-nginx-how-to-run-sudo-at-shell-exec
環境:
AWS
nginx
PHP
だけどバージョンとかWEBサーバの種類とか関係ないです、これ。
実現したいこと:
WEB画面からPHPでスクリプトファイルをキック
(ユーザ:nginx)
↓
nginxユーザはコンソールが無いので
sudoで「soushin」ユーザに切り替えて
スクリプトファイル中のrsyncをsshで実行
↓
画面に実行結果を返す
やったこと:
visudoでnginxにrsyncのパスワードなしでの実行権限を付与
%nginx ALL=(soushin) NOPASSWD:/usr/bin/rsync
ALL=(all)ってなってることが多いのに(soushin)とした理由は
allにしたらrootにもなれちゃうでしょ!危ないでしょ!ということ。
20170518追記:
実際にはrsyncなんていう恐いコマンドを許可せずに
(soushinユーザで何でもかんでもrsyncできるようになってしまう)
スクリプトファイルの方を許可するのが良かとですが
なにしろ開発サーバと同期する先が本当は20か所ぐらいあるので
こうしてしまった…
(スクリプトファイルの設計で何とかしろよというツッコミは甘受)
結果:
コンソールからPHPを実行 → 成功
WEBブラウザからPHPを実行 → エラー
エラー内容
sudoをつけない → sshの秘密鍵のパスが通らないのでネットワーク系のエラー番号12が出る → logにはその旨出力される
sudoをつける → そもそもsudoが実行できない → rsyncのエラーではないのでrsyncのlogにはエラー出力されない
原因:
nginxユーザにそもそも端末がないため。
コンソール上で曲がりなりにも成功したのは、
コンソール自体がnginxの疑似端末として機能したから。
WEBサーバ経由では端末が無いので失敗する。
対策:
sshを通すだけなら -t オプションをつけることで
端末があるように見せかけることができるのだが、
rsync内でsshを走らせているのでこの方法では成功しなかった
(だからハマったのだが)。
よって、sudo visudoにて
Defaults:nginx !requiretty
の1行を追加。
これで端末のないnginxユーザに疑似端末が付与される
端末のないnginxユーザでもsudoできるようになる。
(rryuさま、ご指摘ありがとうございます)
ちなみにスクリプトファイルにSUIDの付与では上手くいかなかった。
おまけ
PHP上でシェルスクリプトを動かすなら、
shell_exec()、exec()、passthru()といろいろあるが
得られる出力結果がちょっとずつ違うので必要に応じてお好みで。
あと、rsyncをお試しになるときは
--dry-run(-n)オプションが疑似実行結果を返してくれるだけなので
いきなりrsyncが走り出すこともなくて便利。