Samba 挂载完文件全是 nobody:uid、gid 和 force user 到底改哪边

举报
phantomxjc 发表于 2026/09/22 08:55:48 2026/09/22
【摘要】 上周在飞牛NAS上开了个SMB共享,打算让内网那台Ubuntu小主机挂上去做备份目录。挂载本身很顺利,一行命令就上去了,结果脚本一跑就崩:PermissionError:Errno13Permissi

上周在飞牛 NAS 上开了个 SMB 共享,打算让内网那台 Ubuntu 小主机挂上去做备份目录。挂载本身很顺利,一行命令就上去了,结果脚本一跑就崩:

PermissionError: [Errno 13] Permission denied: '/mnt/nas/bak/2026-09-22.sql'

ls -l 一看,整个目录的文件属主全是 nobody nogroup。我当时下意识以为是 NAS 那边共享权限没放开,跑去后台把「读写权限」开关来回拨了两次,没用。折腾了小半天才想明白——这事儿得先分清是哪一边的属主在生效。

先把现象看准:用 ls -n 而不是 ls -l

ls -l 会把 uid 翻译成用户名,跨机器的时候这个翻译经常骗人。直接看数字:

ls -n /mnt/nas/bak

65534 就是 nobody。我的备份脚本跑在 backup 用户下,uid 1001,写进一个属主是 65534、权限 644 的目录里,自然被拒。

再看一眼挂载参数,问题就清楚了:

mount | grep cifs
# //192.168.1.20/backup on /mnt/nas type cifs (rw,relatime,vers=3.1.1,cache=strict,username=nas,uid=0,...)

我挂载的时候压根没指定 uid / gid,客户端就用了默认值,于是所有文件在 Linux 这边都显示成 nobody。

客户端这一侧:uid、gid、file_mode、dir_mode

cifs 挂载是「无属主映射」的文件系统——SMB 协议传过来的只有 SID,不带 POSIX uid。所以本地显示成谁,完全由挂载选项决定。最直接的修法:

sudo mount -t cifs //192.168.1.20/backup /mnt/nas \
  -o username=nas,password=xxxx,vers=3.1.1,\
uid=1001,gid=1001,file_mode=0644,dir_mode=0755

几个点值得留意:

  • uid / gid 写数字比写用户名稳。我试过写 uid=backup,在早期内核上翻不出来,直接退化成 nobody。
  • file_mode / dir_mode 只在服务端不支持 CIFS Unix 扩展时才生效。如果 NAS 那边开了 unix extensions,权限以服务端为准,这两个参数会被忽略——这也是很多人「明明配了却不生效」的原因。
  • 别忘 vers=。不写的话内核会先试 SMB1,现在很多 NAS(包括飞牛)默认关了 SMB1,日志里会蹦一句 Operation not supported,内核再回退到 3.x。显式写 vers=3.1.1 能省掉这次无谓的协商。

写进 /etc/fstab 长期挂载时,密码别明文:

# /etc/fstab
//192.168.1.20/backup  /mnt/nas  cifs  credentials=/etc/samba/nas.cred,vers=3.1.1,uid=1001,gid=1001,file_mode=0644,dir_mode=0755,_netdev,nofail  0  0

/etc/samba/nas.cred 内容:

username=nas
password=xxxx
domain=WORKGROUP

这里有个坑我踩过:cred 文件里 username = nas 这种带空格的写法是错的,会被当成用户名的一部分(前面多一个空格),认证必失败。等号两边不要有空格。文件本身 chmod 600,否则 mount 会拒绝加载。

改完先别急着重启,mount -a 试一次,dmesg | tail 看有没有 CIFS 报错,能挂上再重启。

服务端那一侧:force user 才是"统一属主"的正解

客户端改 uid 只是让这台机器看着对。如果同一个共享还要被 Windows、另一台 Linux、Docker 容器同时写,各挂各的 uid,最后 NAS 上存的文件属主会很乱,备份脚本换个机器跑就又挂了。

这种情况应该在服务端收口。ssh 进 NAS(或者直接在 SMB 配置里加),smb.conf 对应共享段:

[backup]
   path = /volume1/backup
   valid users = nas
   read only = no
   force user = nas
   force group = users
   create mask = 0664
   directory mask = 0775

force user = nas 的意思是:不管谁连进来,创建文件时一律以 nas 这个本地账号落盘。这样多端写入的属主就统一了,客户端那边只需要保证能读能写,不必强求 uid 一致。

改完用 testparm -s 校验配置有没有语法错,然后 smbcontrol all reload-config 重载,不用重启整个服务。

顺带记两个相关的坑

NFS 的 root_squash。 如果走的是 NFS 而不是 SMB,root 写入后被映射成 nobody 是正常设计,不是 bug。服务端默认开 root_squash,把客户端的 root 压成 nobody。要么在 /etc/exports 里对可信内网段用 no_root_squash(有安全风险,谨慎),要么客户端用非 root 用户写,要么指定 anonuid=1001,anongid=1001。判断方法:

cat /proc/mounts | grep nfs
showmount -e 192.168.1.20

Docker 容器里挂 cifs。 在容器里直接 mount -t cifs 需要 --cap-add SYS_ADMIN --cap-add DAC_READ_SEARCH,而且要 --device /dev/fuse(走 fuse 的话)。我个人的做法是在宿主机挂好,再用 -v /mnt/nas:/data 挂进容器——容器里看到的 uid 就是宿主机那个 uid,只要和容器里跑进程的用户对上就行,比在容器里折腾 mount 省心得多。

排查顺序

下次再遇到类似问题,我按这个顺序走,基本两分钟定位:

  1. df -T 确认到底挂没挂上、什么类型
  2. mount | grep cifs 看挂载选项里有没有 uid/gid
  3. ls -n 看数字属主,别被用户名翻译误导
  4. 服务端的活:testparm -s 看 force user / create mask
  5. 都对了还写不进,再看目录本身的 POSIX 权限和上级目录的 x 位(没 x 位连 cd 都进不去,报错同样是 Permission denied)

说到底就一句话:SMB 挂载的属主是客户端挂载选项决定的,落盘属主是服务端 force user 决定的。以前我一直以为是共享权限开关没打开,其实那玩意儿跟 nobody 半点关系都没有。

作者:phantomxjc

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。