OpenBSDのchrootはガチである
概要
0 はじめに-nginxの例
OpenBSDは、ともかく<お堅い>ので、普通のノリで<ま、nginxで、ホスト作るか>的にやると、動きません。
OpenBSDのpkg_addで、nginxをインストールしたとしましょう。
一通り設定をおえて、 /var/www/に、自分のホームディレクトリにつくってあるmysiteというパスを<シンボリックリンク>で作るとします。
doas ln -s /home/自分/web/mysite /var/www/
もうこの時点で駄目です。
なぜなら、chrootが、/var/wwwでハードコーディングされており、それが、nginxの<プロセス挙動ルート>です。
その外の場所にあるものは、シンボリックリンクでは、使えません。
あるいは、外部のホスト名をIPで引くような(あるいはその逆)スクリプト(たとえばphpなりpythonなり)を、WEBで動作させようとします。
そのままでは、エラーとなります。なぜか?。nginxのchrootが、/var/wwwですので、/etc/resolv.confは<外部>なので見に行けないのです。
なので、
mkdir /var/www/etc
cp /etc/resolv.conf /var/www/etc
が必要です。(もちろんシンボリックリンクでは無理です)。
つまり、OpenBSDでは、chrootはがちに機能しています。(機能するようにパッケージも作ってあります)。
サーバ用デーモン(relaydなりOpenSMTPDなり)をいじる場合は、こいつを常に意識しておく必要があります。
じゃあ、<あたいのmysiteはどうするんだ?>ということになりますが、これは、明示的にnginxのchrootを<外す>ようにします。
rcctl set nginx flags “-u”
これで、とりあえず、これでシンボリックリンクがきくので
ln -s /foo/bar/website /var/www
などとすると、/var/www配下としてファイルアクセスは可能となります。
でも、これは、決して /var/wwwから全部自由になったわけではありません。
というのも、/var/wwwが、OpenBSD版のnginxにはハードコーディングされているので、そこから自由になるのはなかなか難しいです。
nginxには、flags -p オプションというのがあって、
rcctl set nginx flags "-u -p /home/www"
などとすると、一見nginxのrootが、/home/wwwに変わるように<見えます>。
が、マスタープロセス(動作初期化)での挙動には関係しません。そこで、いろいろなズレが生じます。
1. OpenBSDの発想
-
ネイティブプログラム(httpd, relayd など)
→ プログラム自身が privilege separation / pledge / unveil でセキュリティを担保する -
外来プログラム(nginx など ports)
→ 後付けで chroot をかけて「檻に入れる」ことで暴れる範囲を制限する
この「後付け」が原因で、パス解釈に不整合が生まれやすいようです。
2. マスターとワーカーの区分が重要
| プロセス | タイミング | 主な役割 | パスの扱い |
|---|---|---|---|
| マスター | chroot 前 | 設定ファイル読み込み、証明書オープン、ワーカー起動 | 絶対パスが有効(/etc/nginx, /etc/ssl, /etc/letsencrypt など) |
| ワーカー | chroot 後(-uなしの場合) |
リクエスト処理、ソケット接続、ファイルアクセス | chroot内のパスが見える |
/etc/resolv.conf→ ワーカーが使うので、chroot内にコピーが必要- 証明書や設定 → マスターが読むので絶対パスでOK
3. ランタイムオプションの効果
-
-u
chroot を完全に無効化。ワーカーも実ファイルシステムを見る。
→ シンボリックリンクが使えるようになります。 -
-p /path
prefix を上書きする。
→ 一部有効(相対パスの logs/ や cache/ などには効く)。
→ しかしコンパイル時のNGX_PREFIX=/var/wwwハードコードや、chrootパッチのngx_strip_chroot()と完全には噛み合わなくなります。 → 特に unix ソケット周りでパス解釈がブレて「はまる」という次第。
4. 実践的な落としどころ
-p は使わず、以下で逃げるのが安定します:
rcctl set nginx flags "-u"
- コンテンツは容量の多い /home に置いて、/var/wwwにシンボリックリンク
- nginx 側は従来通り /var/www を基準に動かす
- つまりは、document rootを除き、ハードコードされた /var/www に従いましょう。
これなら -p による複雑なパス解釈の問題を避けられまずし、ドキュメント容量を気にすることもなくなります。
5. PHP-FPM(unixソケット)で問題が顕在化する理由
静的ファイルだけなら、-pもつけても比較的素直に動くんですが、 PHP-FPM を入れると、迷路に陥ります。
- nginx 側のパス解釈(後付けパッチ + prefix)
- PHP-FPM 側のパス関連パラメータ(
listen,chroot,chdir,SCRIPT_FILENAMEなど)
この2つが衝突するようです。
特に:
- ソケットパスは「ファイルを読む」のではなく「
connect()するアドレス」 -uを使っている場合は絶対パスで書いても動く- しかし
-pを併用すると解釈が崩れて破綻しやすい、ということになります。
6. まとめ
- 後付けの chroot パッチが、元の nginx のパス設計と完全に整合していない感じ
- その不整合は マスター/ワーカーのタイミング差 と unixソケット で表面化します
-pは一部有効だが、完全には解決しないです(というか、はまる原因になりやすい)- 実践では
-u+ シンボリックリンク で逃げつつ、仕組みとしては「後付け改変によるパス解釈の不整合」だと理解しておいて、幸せを追求するほうがいいのでは、というのが暫定結論。