Article
PVE の unprivileged LXC コンテナに bind mount した volume を Samba サーバで共有する
Proxmox VE 上の LXC コンテナで Samba 共有を構築し、unprivileged LXC の UID/GID マッピング、bind mount したホストの volume 共有設定を検証した記録です。
はじめに
この記事では、Proxmox VE(以下 PVE)上に作成した LXC コンテナで Samba サーバを構築した検証内容をまとめます。
当初は「自宅内のネットワークだし、ゆるい設定で共有ファイルが見られればいいか」程度の気持ちで始めましたが、PVE や LXC ならではの問題に遭遇しました。
- Samba 共有ディレクトリ自体の参照は可能だが、その配下のファイルやディレクトリが表示されない
- LXC 内のユーザが全て nobody 扱いとなり、PVE ホスト上の volume に Samba 経由で書き込みできない
最終的には、unprivileged LXC における UID / GID マッピングを正しく設定したことで、期待通り動作しました。
構成は以下の通りです。
public共有はゲスト読み取り専用private共有は特定ユーザのみアクセス可能private共有では Samba 経由の書き込みも可能- PVE の LXC mount point で共有対象ディレクトリを Samba 経由で共有
- unprivileged LXC の UID/GID マッピング範囲を把握し、PVE ホスト側の volume 内で正しい UID/GID を指定し権限を調整
検証環境
| 項目 | 内容 |
|---|---|
| 仮想化基盤 | Proxmox VE |
| コンテナ | Debian 系 LXC コンテナ |
| コンテナ名 | `debian-samba` |
| 共有元ストレージ | PVE ホストにマウントした外部ディスク |
| PVE ホスト側パス例 | `/mnt/local/disk1` |
| LXC 内パス例 | `/shared/public`, `/shared/private` |
| Samba ユーザー | `takashi` |
| LXC 内 `takashi` UID/GID | `1000:1000` |
| PVE ホスト側対応 UID/GID | `101000:101000` |
| 接続元クライアント例 | `192.168.1.7` |
最終的な設定
以下のように、読み取り専用の公開共有と、認証付きの書き込み可能な private 共有を分ける構成にしました。
[public]
path = /shared/public
browseable = yes
guest ok = yes
read only = yes
force user = nobody
[private]
path = /shared/private
browseable = no
guest ok = no
read only = no
force user = takashi
force group = takashi
create mask = 0660
directory mask = 0770
force create mode = 0660
force directory mode = 0770private 共有は書き込み可能にするのと、ファイルやディレクトリの所有者を統一するため、PVE ホストの外部ディスク上の権限を LXC 内の takashi に対応する UID/GID に合わせました。
LXC 内 takashi: 1000:1000
PVE ホスト側対応 ID: 101000:101000手順
1. 最初の Samba 共有設定
まずは以下のような読み取り専用の public 共有を設定します。
[public]
path = /shared/public
browseable = yes
guest ok = yes
read only = yes
force user = nobody
inherit permissions = yesこの設定で、とりあえず外部 PC から /shared/public 自体は参照できましたが、その下のファイルやディレクトリが参照できませんでした。
2. nobody ユーザで見えるか確認
force user = nobody を設定したため、Samba は共有内のファイルを nobody として読みに行きます。
まず LXC 内で nobody ユーザーとして /shared/public を読めるか確認すると…
runuser -u nobody -- ls -la /shared/public実際の出力は以下です。
root@debian-samba:/shared/public# runuser -u nobody -- ls -la /shared/public
total 8
drwxrwxrwx 2 root root 4096 Apr 4 14:54 .
drwxr-xr-x 4 root root 4096 Apr 4 14:52 ..
lrwxrwxrwx 1 root root 24 Apr 4 14:52 pictures -> /mnt/bind/disk0/pictures
lrwxrwxrwx 1 root root 22 Apr 4 14:53 videos -> /mnt/bind/disk0/videos
root@debian-samba:/shared/public#この時点では、/shared/public の中身は実体ディレクトリではなく、すべて外部ディスクへのsymbolic linkにしていましたが、wide links 設定をしていませんでした。
3. /etc/pve/lxc/<CTID>.conf に mount point を直接記述
Samba では、共有ディレクトリ外を指す symbolic link を辿るには wide links を設定すべきですが、共有ルート外のパスを辿れるようにすると、意図しないパスを公開してしまうリスクがあるため、避けることにしました。
そこで、public に symbolic link を束ねる構成をやめて、PVE の LXC mount point でコンテナ内に通常のディレクトリとして見せることにしました。
PVE では、pct set コマンドを使って LXC の mount point を設定できます。
pct set <CTID> -mp1 /mnt/host/disk0/pictures,mp=/shared/public/pictures
pct set <CTID> -mp2 /mnt/host/disk0/videos,mp=/shared/public/videos今回は pct set の代わりに、/etc/pve/lxc/<CTID>.conf を直接編集して mount point を設定しました。
直接編集した場合、設定ファイル自体は保存時点で PVE に反映されます。
LXC が起動中の場合、mount point の追加・変更を有効にするには基本的にコンテナの再起動が必要でした。
pct stop <CTID>
pct start <CTID>これで、Samba 共有が期待通りに動作するようになりました。
4. 書き込み権限設定
外部 PC から Samba 共有ドライブを参照できるようになったあと、次に書き込みができない問題に遭遇しました。
PVE ホスト上で外部ディスクを確認すると、以下のように見えていました。
root@pve:~# ls -al /mnt/local/disk1/
total 56
drwxrwxr-x 11 _chrony _ssh 4096 Mar 30 21:40 .
drwxr-xr-x 6 root root 4096 Mar 31 16:37 ..
drwxrwxr-x 14 _chrony _ssh 4096 Mar 30 21:35 pictures
drwxrwxr-x 5 _chrony _ssh 4096 Feb 11 2025 videos_chrony ユーザーや _ssh グループが表示されていますが、これは以前この外部ディスクを接続していたマシン上の UID/GID が、PVE ホスト上では別のユーザー名・グループ名として解釈されていただけです。
一方、LXC 内では以下のように見えていました。
takashi@debian-samba:/shared/private/disk1$ ls -al
total 56
drwxrwxr-x 11 nobody nogroup 4096 Mar 30 12:40 .
drwxr-xr-x 4 root root 4096 May 6 09:04 ..
drwxrwxr-x 14 nobody nogroup 4096 Mar 30 12:35 pictures
drwxrwxr-x 5 nobody nogroup 4096 Feb 11 2025 videosこの nobody:nogroup 表示は、「本当に nobody が所有している」というより、LXC の UID/GID マッピング上、コンテナ内から正しく扱えない UID/GID がそう見えているだけです。
privileged LXC と unprivileged LXC の確認
unprivileged LXC かどうかは、PVE ホスト上で以下のように確認できます。
pct config <CTID>以下の出力があれば unprivileged LXC です。
unprivileged: 1LXC 内で以下コマンドを実行すると、UID/GID マッピングを確認できます。
cat /proc/self/uid_map
cat /proc/self/gid_mapunprivileged LXC では、以下のようなマッピングが典型例のようです。
0 100000 65536これは、LXC 内の UID 0 から 65536 個分が、PVE ホスト側の UID 100000 以降に対応することを意味します。
つまり、LXC 内の takashi が UID 1000 の場合、PVE ホスト側では UID 101000 として扱われます。
この UID/GID マッピングは PVE 独自の仕組みではなく、Linux カーネルの user namespace を LXC が利用しているものです。PVE はその設定を管理しやすく提供しているに過ぎません。
PVE ホスト側で UID/GID を指定して権限を変更
これまでの調査で、以下いずれかを実施すれば書き込み可能になると考えました。
- PVE ホスト側に UID 101000 のユーザーを作る
- PVE ホスト側で bind mount 対象 volume 内のファイルに UID/GID を指定して権限を変更する
今回採用したのは 2. で、以下のコマンドを実行しました。
chown -R 101000:101000 /mnt/local/disk1これにより、外部 PC から Samba 経由で問題なくファイルに書き込みできました。
ただ、PVEホスト上には UID 101000 ユーザが存在しないため、ファイルの所有者が 101000:101000 のような数値 ID として見えてしまいますが、それは許容することにしました。
5. Samba 設定の整理
public 共有
public はゲスト読み取り専用の共有として割り切りました。
[public]
path = /shared/public
browseable = yes
guest ok = yes
read only = yes
force user = nobodyread only = yes のため、以前設定していた inherit permissions = yes は不要と判断し、削除しました。
private 共有
private は認証済みユーザのみアクセス可能としました。
[private]
path = /shared/private
browseable = no
guest ok = no
read only = no
force user = takashi
force group = takashi
create mask = 0660
directory mask = 0770
force create mode = 0660
force directory mode = 0770force user = takashi と force group = takashi を入れた理由は、Samba 経由で作成されるファイルの所有者・グループを明確に揃えるためです。
今回の構成では、PVE ホスト側のファイル所有者を 101000:101000 に寄せています。これは LXC 内の 1000:1000 に対応します。そのため、Samba 側でも takashi に寄せた方が管理が楽と判断しました。
6. smbd 再起動
設定変更後、以下コマンドで Samba 設定が正しいか検証します。
testparm実際の出力は以下です。
root@debian-samba:~# testparm
Load smb config files from /etc/samba/smb.conf
Loaded services file OK.構文として問題ないことを確認した後、smbd を再起動します。
systemctl restart smbdステータス確認結果は以下の通りで、smbd が正常に起動していることがわかります。
root@debian-samba:~# systemctl status smbd --no-pager
* smbd.service - Samba SMB Daemon
Loaded: loaded (/usr/lib/systemd/system/smbd.service; enabled; preset: enabled)
Active: active (running) since Sat 2026-05-23 10:22:41 UTC; 26s ago
Invocation: d512a9f020824b79aa553afe81eb4d18
Docs: man:smbd(8)
man:samba(7)
man:smb.conf(5)
Process: 1022 ExecCondition=/usr/share/samba/is-configured smb (code=exited, status=0/SUCCESS)
Process: 1025 ExecStartPre=/usr/share/samba/update-apparmor-samba-profile (code=exited, status=0/SUCCESS)
Main PID: 1026 (smbd)
Status: "smbd: ready to serve connections..."
Tasks: 4 (limit: 37909)
Memory: 11.5M (peak: 12.1M)
CPU: 264ms
CGroup: /system.slice/smbd.service
|-1026 /usr/sbin/smbd --foreground --no-process-group
|-1030 "smbd: notifyd" .
|-1031 "smbd: cleanupd "
`-1032 "smbd: client [192.168.1.7]"
May 23 10:22:41 debian-samba systemd[1]: Starting smbd.service - Samba ......
May 23 10:22:41 debian-samba systemd[1]: Started smbd.service - Samba S...on.
May 23 10:22:43 debian-samba smbd[1032]: pam_unix(samba:session): sessi...=0)
Hint: Some lines were ellipsized, use -l to show in full.以下から 192.168.1.7 のクライアントから接続が来ていることも確認できます。
smbd: client [192.168.1.7]最終確認結果
最終的に、外部 PC から private 共有にアクセスして以下を確認できました。
- ゲストでは
privateにアクセス不可 takashiではprivateにアクセス可能takashiではprivateに書き込み可能
得られた知見
今回の検証から得られた知見は以下です。
- Samba 共有内で symlink を使って共有ルート外を指す構成は、期待通りに動かないことがあります。
- PVE + LXC では、symlink で逃げるより mount point で正しく見せる方が堅実です。
- unprivileged LXC では、コンテナ内 UID/GID と PVE ホスト側 UID/GID がずれます。
- LXC 内 UID 1000 は、標準的なマッピングでは PVE ホスト側 UID 101000 として扱われます。
- Samba の書き込み問題は、Samba 設定だけでなく Linux ファイル権限と UID/GID マッピングを含めて見る必要があります。
force user/force groupを使うと、Samba 経由で作成されるファイルの所有者を揃えやすくなります。testparmとsystemctl status smbdによる確認は、設定反映後の基本チェックとして有効です。