手上有一台阿里云服务器,跑着几个内部服务,平时用它存一些日志归档、设计素材和给同事分发的安装包。最初的做法是 SFTP 上传下载,用了两个月实在受不了——同事要个 200MB 的素材包,得先下载到本地再传给别人,中间还要解释"你装个客户端"。后来换成对象存储,但每次生成分享链接、设置有效期又太琐碎。最后我决定在 Ubuntu 上装 Samba,把这些目录直接共享出来,Windows、macOS、Linux 三种客户端都能像访问本地磁盘一样双击打开。麻烦的地方在于,这是一台公网服务器,Samba 默认的 445 端口在公网上经常不通,于是又牵扯出端口映射、云平台安全组、系统防火墙这一整条链路。这篇就把从装包到跑通、从权限理清到排错收口的全过程写下来,Ubuntu 20.04/22.04/24.04 都适用,新手照着做能跑通,有经验的人可以重点看权限对齐和端口映射那两节。
1. 云服务器上跑Samba到底值不值:三个合适场景和两类劝退情况
1.1 从"上传下载"到"像本地磁盘一样用"
Samba 做的事说穿了很简单:在 Linux 上实现 SMB/CIFS 协议的服务端,让 Windows 的原生文件共享协议、macOS 的 Finder、Linux 的 cifs 内核模块都能挂上来。它和 SFTP、HTTP 下载最大的区别是挂载之后它是一个文件系统,而不是一个传输通道。这个差别带来的体验是量级的:你在 Windows 资源管理器里输入\\服务器IP\share,回车,输入一次账号密码勾选记住,之后这个目录就一直在"此电脑"里,双击打开、拖拽文件、右键新建文件夹、Office 直接"另存为"到这个路径,全部是原生操作。
我在实际使用中感受最深的是三类场景。第一类是团队内部的文件分发:设计稿、测试包、数据集,放到共享目录里,同事自己取,不用我反复发链接。第二类是跨设备同步工作目录:家里台式机、公司笔记本、虚拟机里的 Ubuntu,同一份代码草稿或者论文素材放在共享目录里,谁都能读写,省掉了 U 盘和聊天软件传来传去。第三类是给容器和虚拟机当"外挂盘":宿主机挂一个共享目录,虚拟机里mount -t cifs上去,改代码不用重启虚拟机,比共享文件夹方案更稳定。
这三类场景有个共同点:访问频率不高但单次文件不小,而且参与的人或设备只有几个。这正好落在 Samba 的舒适区里。如果你的场景偏离这个范围太远,下面这几种情况我建议先别折腾。
1.2 什么情况下我会劝你先别装Samba
第一种是只需要单向读取、几乎没有写入。比如你只是想给一个静态资源目录做个下载入口,那用 Nginx 的autoindex或者对象存储更省事,Samba 的账号体系、端口、防火墙配置一整套下来,成本明显更高。
第二种是多人高频并发写同一个文件。SMB 有文件锁机制,但它是为"一个人打开一份文档编辑"设计的,不是为"五个人同时往一个文件里追加日志"设计的。数据库文件、Git 仓库的.git目录、正在被编译的构建产物,都不要放在 Samba 共享里直接操作,你会遇到文件锁冲突、写入不完整、甚至索引损坏。这类需求应该走版本控制或者专门的同步工具。
第三种最需要说清楚:敏感数据不要裸奔在公网。Samba 老版本默认允许 SMB1、允许匿名访问,这些默认值在公网上就是风险敞口。如果确实要公网访问,那必须走非标准端口、强制 SMB3 加密、账号强密码、安全组限定源 IP 这一整套收口动作,具体在第八节展开。
2. 动手前的环境盘点:Ubuntu版本、网络出口和云平台安全组
2.1 三条命令把家底摸清
在敲apt install之前,我习惯先把三件事确认一遍,这三件事任何一件不对,后面都会白折腾。
# 系统版本与内核 lsb_release -a uname -r # 网卡与内网地址 ip -4 addr show # 当前对外出口地址(确认公网 IP 是弹性 IP 还是 NAT 出口) curl -s ifconfig.me; echolsb_release -a看的是发行版版本,Ubuntu 20.04 自带 Samba 4.11,22.04 是 4.15,24.04 是 4.19,这几个版本的配置文件语法基本兼容,但 24.04 在默认协议上更严格,老客户端如果只支持 SMB1 会直接连不上,这一点后面会细说。
ip -4 addr show输出的地址很关键:阿里云 ECS 的网卡上看到的一般是内网地址(10.x、172.16.x 段),公网 IP 是通过 NAT 映射到这张网卡上的。这意味着 Samba 配置里不要写死公网 IP,interfaces和bind interfaces only这类参数能不写就不写,让它默认监听所有地址最省心。
2.2 阿里云安全组:公网访问绕不过去的第一道门
这是新手最容易卡住的地方:服务明明起来了,systemctl status smbd一片绿,本机smbclient也能连上自己,但外网死活连不上。九成以上的原因在安全组。
阿里云的入方向规则是按协议 + 端口范围 + 授权对象三个维度配的。你需要开的是:
| 协议 | 端口 | 用途 | 授权对象建议 |
|---|---|---|---|
| TCP | 445 | SMB over TCP,现代 Windows/macOS 首选 | 自己的固定出口 IP/32 |
| TCP | 139 | 老客户端走 NetBIOS over TCP 时用 | 同上,不用可不加 |
| UDP | 137-138 | NetBIOS 名称解析,仅局域网式广播场景需要 | 一般不用加 |
| TCP | 4450 | 自定义映射端口(示例) | 自己的固定出口 IP/32 |
授权对象那一栏我要多说两句。很多人图省事填0.0.0.0/0,等于把共享目录挂到全世界面前。只要有一台机器被扫到,弱口令爆破是几小时内的事。正确做法是填自己家的宽带出口 IP 加/32,公司如果也是固定出口就再添一条。/32 的意思是这个地址段里只有这一个 IP,比填一个 C 段安全得多。宽带的公网 IP 会变,隔段时间连不上就回来改一下,这个麻烦值得吃。
2.3 系统防火墙:ufw 和 firewalld 的选择
Ubuntu 默认装的是 ufw,但默认状态是未启用(inactive)。这里有个取舍:
- 只用安全组,不开 ufw:配置最省事,但安全组一旦被人误改,主机就完全没有第二道防线。
- 两者都开:安全组做粗粒度控制,ufw 做主机层面的细粒度控制,我推荐这个方案。
ufw 的放行写法注意要用 Samba 的应用配置文件,它会一次性把该放的端口放对:
ufw allow from 203.0.113.10 to any port 4450 proto tcp ufw allow Samba ufw status verbose第二条ufw allow Samba会自动套用/etc/ufw/applications.d/samba里的定义,把 137/138/139/445 一起放行。如果你改成了自定义端口 4450,那就用第一条那种显式写法,别依赖应用配置文件。
注意:ufw 默认会拒绝所有入站,所以在
ufw enable之前一定确认 SSH 的 22 端口已经放行,否则会把自己关在门外。云服务器上这一点比本地机器更要命,因为控制台的 VNC 救援入口操作起来很别扭。
3. 安装Samba与最小可用配置的落地过程
3.1 apt 安装与版本确认
安装本身一行命令,但后面的确认步骤别省:
sudo apt update sudo apt install -y samba samba-common-bin smbd -V systemctl status smbd --no-pagersmbd -V打印的是实际生效的版本号,比apt policy samba更可信。安装过程会自动生成一份/etc/samba/smb.conf默认配置,同时创建smbd和nmbd两个 systemd 服务。这里有个细节:Ubuntu 上 smbd 和 nmbd 是分开的两个 unit,你在局域网里靠"网络邻居"浏览共享依赖 nmbd,但如果是通过\\IP\share直接访问,其实只用 smbd 就够了。我一般两个都留着。
systemctl status smbd显示active (running)就说明服务起来了,但这只是"能启动",不代表"能连上",配置对不对还得看下一节。
3.2 smb.conf 的结构:global 段管全局,共享段管目录
/etc/samba/smb.conf的语法非常朴素,只有两种东西:节(section)和参数(parameter)。节用方括号包起来,[global]是唯一有特殊地位的节,里面的参数作用于整个服务;其他节名就是共享名,客户端看到的就是这个名字。
注释支持#和;两种,但有个坑要提:参数值里的;和#也会被当成注释起始符,比如你在某个路径里带了#,会被截断。所以路径里尽量别用这两个符号。
另外推荐一个组织方式,从 Samba 4.0 起官方配置末尾就有这几行:
include = /etc/samba/smb.conf.%U include = /etc/samba/smb.conf.%G%U是登录用户名,%G是用户主组。这意味着你可以给每个用户单独放一份覆盖配置,把个性化的东西(比如专属目录)写在/etc/samba/smb.conf.zhangsan里,主配置保持干净。团队人多的时候这个机制非常好用,主配置只用管公共共享。
3.3 一份能跑起来的最小配置
下面这份配置我用了很久,思路是"先把只读共享跑通,再逐步加可写共享":
[global] workgroup = WORKGROUP server string = Cloud File Server security = user map to guest = never server min protocol = SMB2_10 client min protocol = SMB2_10 unix charset = UTF-8 dos charset = CP936 log file = /var/log/samba/log.%m max log size = 1000 logging = file log level = 1 [public] comment = Public Read Only path = /srv/samba/public browseable = yes read only = yes guest ok = no valid users = @smbusers create mask = 0644 directory mask = 0755 [team] comment = Team Writable Share path = /srv/samba/team browseable = yes read only = no guest ok = no valid users = @smbusers write list = @smbusers force group = smbusers create mask = 0660 directory mask = 2770几个参数值得单独解释。server min protocol = SMB2_10是为了关掉 SMB1——SMB1 是 1980 年代的协议,存在大量已知问题,现在的 Windows 10/11 和 macOS 都已经默认不使用了,关掉它没有任何体验损失,只是防止古董设备接入。map to guest = never是彻底禁止匿名访问,任何没有正确凭据的连接直接拒绝,不给它降级成 guest 的机会。
unix charset = UTF-8和dos charset = CP936这对组合是解决中文文件名的。Unix 侧文件名是 UTF-8 存储的,老 Windows 客户端在协商时可能用 GBK 编码,dos charset = CP936让服务端在必要时做转换。新版 Windows 基本都走 UTF-8 了,这个参数留着不碍事。
3.4 改完配置必须跑 testparm
这是我这几年养成的肌肉记忆,比重启服务还重要:
testparm -s它会做两件事:一是检查语法,二是把最终生效的配置(含所有默认值)打印出来。很多人以为自己的配置生效了,其实某个参数写错位置被忽略了——比如把read only写进了[global],它不会报错,但也完全不起作用。testparm -s的输出里能看到这个参数到底有没有落到对应的共享段里。
改完配置不重启也能生效,用这个命令通知 smbd 重载:
sudo smbcontrol all reload-config只有改动smb ports、interfaces这类监听层面的参数时,才必须systemctl restart smbd nmbd。
4. 账号与权限的三方对齐:系统用户、Samba用户、目录归属
这一节是整篇里最容易让人栽跟头的地方,我见过太多人卡在这里。核心原因是:访问一个共享目录,要同时过两套体系的检查。
4.1 为什么系统用户建好了还是登录失败
Samba 用的是 Linux 的系统用户来做身份映射,但密码库是独立的。你useradd建了用户、设了系统密码,Samba 完全不认——它查的是/var/lib/samba/private/passdb.tdb(老版本在/etc/samba/smbpasswd)。所以必须再用smbpasswd -a往 Samba 的密码库里加一份。
顺序上我建议这样:
sudo adduser zhangsan # 建系统用户,会同时建同名组 sudo smbpasswd -a zhangsan # 设置 Samba 密码,交互式输入 sudo smbpasswd -e zhangsan # 确保账号是启用状态 sudo pdbedit -L # 列出所有 Samba 用户pdbedit -L是排查时的第一手工具,输出了用户名和 UID 说明注册成功;如果这里没有你要的用户,那前面smbpasswd -a一定失败了,去看它的报错。
4.2 smbpasswd 的几个常用动作
| 命令 | 作用 | 使用时机 |
|---|---|---|
smbpasswd -a user | 添加并设置密码 | 首次创建 Samba 用户 |
smbpasswd -e user | 启用账号 | 账号被 -d 禁用后恢复 |
smbpasswd -d user | 禁用账号 | 人员离职、临时停用 |
smbpasswd -x user | 删除 Samba 用户 | 彻底移除(不动系统用户) |
smbpasswd user | 修改自己的密码 | 普通用户自助改密 |
pdbedit -L -v | 查看详细账号信息 | 排查账号状态 |
-d和-x的区别值得记住:-d只是标记禁用,随时能-e回来;-x是从密码库里删掉,重新加要重设密码。人员流动频繁的团队,-d更灵活。
4.3 目录权限、create mask 与 force user 的配合
现在说最难的一层:文件系统权限。Samba 拿到登录用户后会切换到对应的 Linux 用户身份去读写目录,所以目录的属主、属组、权限位必须允许这个用户操作。
这里有三组概念容易混:
- 目录本身的权限(
ls -ld /srv/samba/team看到的drwxrws---):决定用户能不能进这个目录、能不能在里面创建文件。 - create mask / directory mask:决定新建的文件和子目录的权限位。注意它只是"允许的最大权限",实际权限还会受 umask 影响,Samba 用的是"请求权限 AND mask"的逻辑。
- force user / force group:强制所有操作以指定的用户或组身份进行,忽略客户端的实际登录身份。
force group是最实用的一个。团队共享目录配上force group = smbusers和create mask = 0660,不管谁来创建文件,文件的属组都是smbusers,组内成员都能读写,不会出现"张三建的文件李四改不了"这种事。
directory mask = 2770里的那个2是SGID 位,它保证在这个目录里新建的子目录自动继承父目录的属组,而不是继承创建者的主组。没有这个位,子目录的属组会变成创建者的默认组,共享结构一深入就全乱了。
4.4 几种常见共享形态的权限方案对照
不同用途的共享目录,权限配法差别很大,我整理成一张表:
| 共享形态 | 目录权限 | 关键参数 | 说明 |
|---|---|---|---|
| 个人私有目录 | drwx------属主自己 | valid users = %U、read only = no | 每人一个目录,互不可见 |
| 团队可写目录 | drwxrws---属主 root:smbusers | force group = smbusers、create mask = 0660、directory mask = 2770 | 组内全员读写,推荐 |
| 只读分发目录 | drwxr-x---属主 root:smbusers | read only = yes、valid users = @smbusers | 管理者单独留写权限 |
| 投递目录(只进不出) | drwx-wx---属主 root:smbusers | read only = no、write list = @smbusers配合目录无读权限 | 收集作业、上传文件,防止互相偷看 |
最后那个"投递目录"值得说一下。给目录设成drwx-wx---(有写无读),用户能往里扔文件但看不到目录里有什么,配合create mask = 0600让上传的文件只有自己能读。这个模式在收集报表、作业、匿名反馈的场景里非常实用,但要注意用户重复上传同名文件时会失败(因为他看不到已存在的文件,却也没权限覆盖),通常要在客户端加时间戳后缀。
目录创建和权限设置的具体命令:
sudo mkdir -p /srv/samba/{public,team,drop} sudo groupadd smbusers sudo usermod -aG smbusers zhangsan sudo usermod -aG smbusers lisi sudo chown root:smbusers /srv/samba/team sudo chmod 2770 /srv/samba/team sudo chown root:smbusers /srv/samba/public sudo chmod 2750 /srv/samba/public改完组关系后,已经登录的会话不会自动获得新组,要么让用户重新登录,要么用newgrp smbusers刷新。这是排查"我明明加了组怎么还是不行"的经典原因。
5. 端口映射实战:把445换成自定义端口打通公网
5.1 为什么公网直连445经常不通
445 端口在公网上的处境很特殊。历史上有多轮大规模的网络蠕虫利用了 SMB 服务的漏洞传播,导致运营商和云平台普遍对 445 做了出入方向的限制。你在家里宽带试,很可能出方向的 445 是直接被拦掉的,表现就是 TCP 握手根本建立不起来,telnet 服务器IP 445一直卡在连接中,而不是快速拒绝。
这种情况下的解决办法就是换一个非标准端口,把 SMB 服务监听在你指定的端口上,然后通过云平台安全组把这个端口映射放行出去。严格说这叫"端口变更 + 安全组放行",云平台的 NAT 网关完成内外网地址的转换,你不需要在阿里云上做额外的 DNAT 配置——安全组放行 + 服务改端口这两步就够了。
5.2 用自定义端口映射的完整配置链
四步,顺序很重要:
# 第一步:改服务监听端口 sudo vi /etc/samba/smb.conf # 在 [global] 段加上: # smb ports = 4450 # 第二步:防火墙放行(只给自己出口 IP) sudo ufw allow from 203.0.113.10 to any port 4450 proto tcp # 第三步:重启服务并验证监听 sudo systemctl restart smbd nmbd ss -lntp | grep -E '445|4450' # 第四步:云控制台安全组入方向添加 TCP 4450 规则ss -lntp的输出是判断成败的关键:应该只看到 4450 在监听,445 消失了。如果两个都在,说明配置没生效或者被别的地方覆盖了,回去跑testparm -s | grep smb\ ports确认。
改端口有个连带影响要提前说:smb ports改了以后,NetBIOS 那一套(137/138/139)实际就废了,靠"网络邻居"自动发现的方式不再工作。这不算问题,因为公网环境本来也不该用广播发现,直接用\\IP:端口\共享名这种显式路径访问更可靠。
5.3 客户端怎么指定端口
这是改端口之后最麻烦的一环,因为不同客户端的支持程度差别很大:
| 客户端 | 指定端口的方式 | 是否原生支持 |
|---|---|---|
| smbclient | -p 4450或--port=4450 | 支持 |
| Linux mount.cifs | 挂载选项port=4450 | 支持 |
| macOS Finder | smb://IP:4450/share | 支持 |
| Windows 资源管理器 | 不支持 | 需本地端口转发 |
Linux 端的实测写法:
# 先探测共享列表 smbclient -L //203.0.113.10 -p 4450 -U zhangsan # 临时挂载 sudo mkdir -p /mnt/team sudo mount -t cifs //203.0.113.10/team /mnt/team \ -o port=4450,username=zhangsan,uid=$(id -u),gid=$(id -g),\ file_mode=0660,dir_mode=2770,iocharset=utf8,vers=3.0 # 查看挂载状态 mount | grep cifsvers=3.0这个选项建议显式写上。老内核默认可能协商到 SMB1,而我们在服务端已经关掉了 SMB1,结果就是挂载时报一个很含糊的协议不匹配错误。写死3.0或3.1.1能省掉一堆排查。
5.4 Windows 客户端在非标准端口下的处理
Windows 资源管理器在地址栏输\\IP:4450\share是不认的,它会报"找不到网络路径"。绕过去的办法是在本机做一个本地端口转发,把本地的 445 映射到服务器的 4450,然后访问\\127.0.0.1\share:
:: 以管理员身份运行 netsh interface portproxy add v4tov4 listenport=445 listenaddress=127.0.0.1 connectport=4450 connectaddress=203.0.113.10 :: 查看已配置的转发 netsh interface portproxy show all :: 删除 netsh interface portproxy delete v4tov4 listenport=445 listenaddress=127.0.0.1这里的关键点是listenaddress=127.0.0.1。Windows 自身的 SMB 服务已经占用了 0.0.0.0:445,如果你监听地址写0.0.0.0,转发规则会添加失败或者不生效。绑定在回环地址上就避开了这个冲突,代价是只能本机访问,对本机映射驱动器来说完全够用。
顺手提醒:端口转发规则是持久化的,重启后仍然存在。如果哪天服务器 IP 变了或者不用了,记得回来delete,否则会出现连到老地址的超时等待,非常难排查。
6. 三种客户端的接入方式与各自的小脾气
6.1 Windows:映射网络驱动器与凭据管理
Windows 端的标准流程是这样:打开"此电脑",右键"映射网络驱动器",文件夹框填\\203.0.113.10\team,勾选"使用其他凭据",输入 Samba 用户名密码,勾选"记住我的凭据"。也可以用命令行一次搞定:
net use Z: \\203.0.113.10\team /user:zhangsan * /persistent:yes net use net use Z: /delete/persistent:yes让它在重启后自动重连,*表示交互式输入密码,避免密码留在命令历史里。
Windows 这边有几个特有的坑。一是凭据冲突:如果你之前用另一个账号连过同一台服务器,Windows 会缓存旧凭据,新账号怎么输都失败,报"多重连接到一个服务器或共享资源"或者直接认证失败。清理方式是在"凭据管理器"里删掉对应的 Windows 凭据,或者用net use * /delete全部断开重来。二是访客访问策略:较新的 Windows 版本默认禁止用 guest 身份做 SMB 访问,如果服务端配了允许 guest 的共享,客户端可能直接拒绝连接,报错代码往往是0x8007052e之类。这也是我一直建议关掉 guest 的原因之一——两边策略不一致会制造很多无谓的排错时间。
6.2 macOS:Finder 的 smb:// 和它在共享目录里留下的垃圾
macOS 接入很简单,Finder 里按Cmd + K,输入smb://203.0.113.10:4450/team,认证后就会挂载到/Volumes/team。命令行方式:
mkdir -p ~/mnt/team mount_smbfs //zhangsan@203.0.113.10:4450/team ~/mnt/team umount ~/mnt/teammacOS 有两个特别烦人的行为。第一是它会在每个目录写.DS_Store元数据文件,在共享目录里一样照写不误,几个月下来目录里全是隐藏文件。第二是在复制包含扩展属性的文件时生成._前缀的伴生文件(AppleDouble 格式),你的服务器目录会被这些文件撑得很难看。
解决办法是在共享段加上过滤:
veto files = /._*/.DS_Store/ delete veto files = yesveto files让服务端直接隐藏这些文件,客户端看不到也写不进去;delete veto files = yes表示删除目录时允许连带删掉被 veto 的文件。这个改动很小,但共享目录的整洁度提升非常明显。
6.3 Linux:cifs-utils 与开机自动挂载
Linux 端的准备工作是先装上工具包:
sudo apt install -y cifs-utils然后把凭据单独放一个文件,避免密码出现在/etc/fstab这个全局可读的地方:
# /etc/samba/cred-team,权限设成 0600 sudo tee /etc/samba/cred-team > /dev/null <<'EOF' username=zhangsan password=你的密码 domain=WORKGROUP EOF sudo chmod 600 /etc/samba/cred-team对应/etc/fstab里的写法:
//203.0.113.10/team /mnt/team cifs credentials=/etc/samba/cred-team,port=4450,vers=3.0,uid=1000,gid=1000,file_mode=0660,dir_mode=2770,iocharset=utf8,_netdev,noauto,x-systemd.automount 0 0这里几个挂载选项各有讲究。_netdev告诉系统这是网络文件系统,等网络就绪后再挂载,不加的话开机时可能因为网络还没起来而挂载失败,进而卡住整个启动流程。noauto表示不随mount -a自动挂载。x-systemd.automount让 systemd 创建一个自动挂载点,第一次访问该目录时才真正去挂载。这个组合是我目前最推荐的:既避免了开机网络竞态,又不需要手动敲 mount。
7. 连不上、能读不能写:按层排查的完整链路
排错最忌讳的是到处乱改配置。我的做法是固定按四层顺序走,每层都有明确的验证命令,确认通过再进下一层。
7.1 第一层:网络层,先确认端口能通
# 从客户端测 nc -vz 203.0.113.10 4450 telnet 203.0.113.10 4450 # 服务器上看监听状态 ss -lntp | grep smbd如果这一层就不通,问题不在 Samba,而在安全组或者 ufw。判断技巧是看报错形态:Connection refused说明包到了服务器但没服务监听,方向是查 smbd;超时卡住Connection timed out说明包被中间设备丢了,方向是查安全组和运营商策略。这两个报错指向完全不同的原因,别混着查。
7.2 第二层:服务层,本机连自己
smbclient -L //127.0.0.1 -p 4450 -U zhangsan smbstatussmbclient -L能列出共享名,说明服务本身和配置没问题。这一步通过但外网不通,就回到第一层继续查网络。smbstatus更有意思,它能看到当前所有活跃连接、锁定的文件、以及每个连接的登录用户,排查"谁占着文件不放"的时候非常有用。
7.3 第三层:认证层,用目标账号实测
smbclient //203.0.113.10/team -p 4450 -U zhangsan # 进入交互后 smb: \> ls smb: \> put /etc/hostname test.txt这一步是分水岭。如果ls成功但put失败,问题在权限层,跟认证无关。如果登录就失败,检查pdbedit -L里有没有这个用户、账号是不是启用状态、密码是不是搞错了大小写。
7.4 第四层:权限层,从文件系统角度复验
ls -ld /srv/samba/team sudo -u zhangsan ls -l /srv/samba/team sudo -u zhangsan touch /srv/samba/team/.perm_test && echo OK最后那条命令是我最爱用的招数:绕开 Samba,直接用目标系统用户的身份去写文件。如果这一步都写不进去,那 Samba 怎么配都没用,是纯文件系统权限问题;如果这一步能写,但通过 Samba 不行,那就是read only、write list、create mask这些 Samba 参数的问题。
7.5 常见报错对照表
| 客户端现象 | 大概率根因 | 验证方式 |
|---|---|---|
| 连接超时,无任何提示 | 安全组未放行 / 端口写错 | nc -vz IP 端口 |
| Connection refused | smbd 未运行或未监听该端口 | ss -lntp | grep smbd |
| 提示用户名或密码错误 | Samba 密码未设置 / 账号被禁用 | pdbedit -L、smbpasswd -e |
| 能看到共享名但点进去报无权限 | valid users不含该用户或组关系未刷新 | testparm -s、重新登录 |
| 能读不能写 | read only = yes/write list限制 / 目录权限不足 | 用sudo -u复验写权限 |
| Windows 报多重连接错误 | 客户端旧凭据冲突 | 凭据管理器清理、net use * /delete |
| 中文文件名乱码 | 字符集参数缺失 | 检查unix charset与客户端编码 |
| 大文件传到一半中断 | 会话超时 / MTU 问题 | deadtime、socket options调整 |
7.6 日志在哪里、怎么开更详细的日志
Samba 的日志默认在/var/log/samba/下,log.%m这个写法会让每个客户端 IP 生成一个独立文件(%m是客户端机器名,实际文件名可能是log.203.0.113.10或者log.desktop-abc)。查的时候先ls -lt /var/log/samba/找最新的那个。
排错时需要临时提高日志级别:
# [global] 段 log level = 2级别 2 会把认证过程、权限检查的关键路径打出来,足够定位绝大多数问题。但排完必须改回 1,级别 3 以上会让日志文件飞速膨胀,几天就能吃掉几个 G 的磁盘,我见过因为这个把系统盘写满导致服务全挂的情况。
8. 挂在公网上的Samba:安全收口与并发调优
8.1 认证层面的几道闸必须先关
公网暴露的服务,安全配置不能靠"应该没人会扫到"。我在[global]段固定加这几行:
security = user map to guest = never guest account = nobody restrict anonymous = 2 server min protocol = SMB2_10 smb encrypt = required obey pam restrictions = yes pam password change = yessmb encrypt = required是这里面最有分量的一条,它强制所有 SMB3 流量加密。这个参数只在 SMB3 下有效,这也是为什么前面要强制server min protocol = SMB2_10——老协议不支持加密,必须一起调。开启加密后有轻微的性能开销,但在公网传文件,这点开销必须接受。
restrict anonymous = 2是彻底拒绝匿名连接,连共享列表都不给匿名用户看。obey pam restrictions = yes让 Samba 遵循系统的账号策略,比如账号锁定规则、密码过期时间,这些在纯 Samba 层是管不到的。
8.2 网络层面的收口手段
除了前面说的安全组限定源 IP,还有两个做法:
一是不用标准端口。这不算真正的安全措施(端口扫描一样能发现),但能过滤掉大量只会扫 445 的自动化脚本,降低被盯上的概率。
二是给认证失败加限制。可以用 fail2ban 监控 Samba 日志里的认证失败记录,连续失败达到阈值就把源 IP 临时封禁:
sudo apt install -y fail2ban # 新建 /etc/fail2ban/jail.d/samba.conf[samba] enabled = true port = 4450 filter = samba logpath = /var/log/samba/log.%m maxretry = 3 bantime = 3600 findtime = 600配置完之后sudo fail2ban-client status samba能看当前的封禁列表。这个组合对暴力破解的效果非常明显,实测下来配上之后日志里的异常尝试会大幅减少。
8.3 性能与稳定性参数
公网传输的两个主要瓶颈是带宽和单连接延迟。Samba 默认的一些参数是为局域网优化的,公网环境下可以调:
socket options = TCP_NODELAY IPTOS_LOWDELAY read raw = yes write raw = yes aio read size = 16384 aio write size = 16384 deadtime = 15 keepalive = 60TCP_NODELAY关掉 Nagle 算法,减少小请求的延迟累积,交互式操作(列目录、打开小文件)体感提升明显。deadtime = 15表示连接空闲 15 分钟就断开,释放服务端资源,避免大量僵尸连接堆积。keepalive = 60每 60 秒发一次探测包,防止中间的 NAT 设备把空闲连接表项回收——这是大文件传输中途断掉的常见原因。
aio read/write size开启异步 IO,大文件顺序读写会有一定提升。但如果你的服务器磁盘本身是云盘、IOPS 有限,这个参数的收益不大,不要指望它能突破磁盘瓶颈。
关于带宽还有个现实提醒:阿里云 ECS 的公网带宽是按购买量计的,如果你买的是 5Mbps 带宽,理论峰值也就 600KB/s 左右,传 1G 的文件要将近半小时。这个跟 Samba 配置没关系,是链路本身的限制。要传大文件要么提带宽(贵),要么走内网(同地域的机器走内网地址,带宽和速度完全是另一个量级)。
9. 我在实际部署里踩过的坑和留下的几个习惯
第一次部署的时候,我在改完smb.conf后忘了重启服务,然后对着smbclient报了半小时的"用户名或密码错误"——因为服务还在用旧配置,而我新加的用户根本不在旧配置的valid users里。从那以后我的固定动作是:改配置 →testparm -s→smbcontrol all reload-config或systemctl restart smbd nmbd→smbstatus确认。这四个动作连成一条肌肉记忆,能省掉大量无意义的调试。
第二个坑是中文文件名。早期配置里只写了unix charset = UTF-8,Windows 客户端传上来的中文文件名在 Linux 侧看是乱码。补上dos charset = CP936之后正常了。后来发现新版 Windows 走 UTF-8 协商就没这个问题,但为了兼容一些老设备,这个参数一直留着。
第三个坑是磁盘写满。有一次开了log level = 3排一个问题,排完忘了改回来,一周后 smbd 突然拒绝服务,查了半天发现是日志目录把系统盘写满了。Samba 的日志级别是排查工具,不是常驻配置,这是我现在写在部署清单第一条的话。
第四个坑是关于force user的误解。我一开始以为配了force user就能无视目录权限,结果发现不是——force user只是切换身份,切换后仍然受该用户对目录的权限约束。如果被强制切换的那个用户对目录没有写权限,照样写不进去。这个理解纠正之后,我在配force user时会同时检查那个用户对目标目录的权限。
最后留下几个习惯,都是被坑出来的:部署完成后立刻把可用的smb.conf备份到/etc/samba/smb.conf.bak.$(date +%F),改坏了随时回滚;目录结构固定用/srv/samba/做根,不散落在/home里,因为/home在有些发行版上有自动挂载和配额策略,会给共享带来额外变量;客户端的凭据文件权限永远设成 0600,服务器上的passdb.tdb也只在备份时导出,不往代码仓库里放。
这套方案我在几台阿里云 ECS 上跑了两年多,日常就三五个人的使用强度,除了偶尔要更新一下安全组里的源 IP(家里宽带换地址了),基本没出过需要紧急处理的问题。真正花时间的从来不是安装那一步,而是把权限、端口、防火墙这三层对清楚,以及养成改配置后验证的习惯。