![[Linux] symlinkとbind mountの実戦比較](https://humanxai.info/images/uploads/linux-symlink-mount.webp)
はじめに
主に自宅サーバ用途として、2000年頃から長く使い続けてきたFreeBSDやLinux系OS。
mount や symlink は最初に環境を構築するとほぼ使わなくなり、余り深く調べてこなかったのと、
ローカルサーバ内でアプリ開発をするようになり、それに伴い、使用頻度が増えてき為、改めて再学習の備忘録を含め、記事に違いをまとめてみました。
仕組みの違い
- symlink=道案内の札
解決はユーザ空間のパス解決で行われ、権限は逸脱できない。
壊れやすい(先が消えると“ダングリング”)。 - bind mount=OSに作る第2の入口(トンネル)
解決はカーネルのマウントテーブルで行われ、同じ実体を別ルートに露出できる。
リブートで消える(fstabやsystemdで永続化が必要)。
symlink(ln -s SRC DST)
- 「DST を開こうとすると、実際は SRC を見に行ってね」というパス置換。
- 別inodeを持つ“リンク用のファイル”。中身は文字列(参照先パス)。
- 参照先が消えると壊れる(dangling symlink)。
- 相対/絶対パスが選べる。相対は移動に強いが、chroot/jail内だと意図通り届かないことも。
bind mount(mount –bind SRC DST)
- 既存ディレクトリ/ファイルを別の場所へ再マウントして見せる。
- 同じinodeを2つ目のマウントポイントから参照する感じ(“同じ実体に別玄関”)。
- ディレクトリもファイルもOK(ファイルbindも可能)。
- rbindでサブマウントも再帰的に露出できる。
- 読み取り専用にしたいときは mount -o remount,bind,ro DST。
2) 権限・セキュリティの差
観点 | symlink | bind mount |
---|---|---|
権限の超越 | できない(参照先の権限が最終決定) | できない(最終的には参照先の権限)が、“どこを見せるか”をOS側で制御できる |
Webサーバのポリシー | ApacheのOptions FollowSymLinks やnginxのdisable_symlinks に引っかかることあり |
シンボリックリンク判定に引っかからない(ポリシー回避に有効) |
chroot/コンテナ | symlinkはroot外(/)を直接指せないことが多い | 必要なサブツリーだけを安全に注入できる(Dockerの-v に近い) |
パス逃げ(../../) | symlink自体はパス。パス検証が甘いとTOCTOUの温床に | bind mountは露出範囲をマウントで固定。アプリ側のパス検証が楽 |
SELinux/AppArmor | symlinkはラベル/プロファイル次第 | 元のラベルを引き継ぐ。ls -Z で確認、必要ならchcon 。 |
実務TIP:Webでsymlink禁止(既定/ポリシー)な環境は多い。
そのときbind mountで“同じ中身”を見せるのが定番回避策。
3) 運用・ツールの差
観点 | symlink | bind mount |
---|---|---|
永続性 | 永続(ファイルとして残る) | 揮発(再起動で消える→/etc/fstab やsystemdで永続化) |
バックアップ/同期 | tar/rsync はデフォでlinkとして扱う(辿らない設定が多い) |
“本物のディレクトリ”に見えるので二重バックアップに注意(除外指定が必要) |
調査コマンド | readlink -f DST で参照先を見る |
findmnt DST / mountpoint DST でマウント状況を確認 |
無限ループ事故 | ln -s . dst などで発生しがち |
自己配下へマウントすると地獄(避ける) |
ファイル監視 | 監視対象は参照先のinode | 同じinodeなので挙動は自然(inotify 等はそのまま動く) |
rsync注意:bind mount は“普通のディレクトリ”扱い。
–one-file-system は同一FS内なので効きにくい。明示的に除外しよう。
4) 具体例:今回のユースケース
Web:/home/www/app から
データ/コード:/var/hoge/data
を読みたい
symlink でやる
# 失敗例になりがち:Webサーバのsymlinkポリシーに阻まれることがある
ln -s /var/hoge/data /home/www/shared/
- ApacheのFollowSymLinks無効や、nginxのdisable_symlinksに引っかかることがある。
bind mount(推奨)
sudo mkdir -p /var/shared/data
sudo mount --bind /home/www/hoge /var/shared/data
# 永続化:/etc/fstab
echo "/home/www/hoge /var/shared/data none bind 0 0" | sudo tee -a /etc/fstab
- Webからは
/var/shared/data
を読むだけ。 - 権限は元側に合わせ、必要ならACLを足す:
sudo setfacl -R -m u:www-data:rx /home/www/hoge
只読で見せたい(事故防止)
sudo mount --bind /home/www/hoge /var/shared/data
sudo mount -o remount,bind,ro /var/shared/data
# fstab例:最後に ,ro を追加
/home/www/hoge /var/shared/data none bind,ro 0 0
systemdでスマートに永続化(fstab嫌い派)
- ユニット名はパスを
-
でつないだもの:/var/shared/data
→var-shared-data
/etc/systemd/system/var-shared-data
[Unit]
Description=Bind mount paypay to web shared
[Mount]
What=/home/www/hoge
Where=/var/shared/data
Type=none
Options=bind,ro
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now var-shared-data
5) 使い分け(現場基準)
-
Web配下に“別場所の中身”を自然に見せたい → bind mount
- symlinkポリシーに阻まれない
- 只読化できる/範囲を限定できる
-
設定ファイルの差し替え、軽い参照 → symlink
- 例:
/etc/nginx/sites-enabled
↔/etc/nginx/sites-available
- 例:アプリ内のテンプレート差し替え
- 例:
-
コンテナ/隔離空間へ必要最小限を露出 → bind mount一択
- chroot/Docker/LXC でのベストプラクティス
6) デバッグ・確認コマンド小箱
# symlinkの行き先
readlink -f /var/shared/data
# bind mountの確認
findmnt /var/shared/data
mountpoint /var/shared/data
# inodeが同じか確認(SRCとDSTで同じ番号なら“同じ実体”)
stat -c '%i %n' /home/www/hoge
stat -c '%i %n' /var/shared/data
7) ブログ向けタイトル案(おまけ)
- 「symlinkとbind mountの実戦比較:Web配下に“別の中身”を安全に見せる最短手順」
- 「シンボリックリンクでは通らない夜:nginx/Apacheで詰まったらbind mountで突破」
- 「C言語のポインタみたいに:Linuxのbind mountを図解で理解する」
💬 コメント