受够了手动配 Samba:一个脚本搞定家里所有 Linux / OpenWrt 的文件共享

random-pic-api

前言

说实话,我被 Samba 配置搞得快疯了。

家里现在有 5 台服务器,有装 Ubuntu 的,有装 CentOS 的,还有两台刷了 OpenWrt 的软路由。每次想共享个文件或者备份点数据,都得去手动配 Samba,真的太烦了。

你可能想,Samba 配置不就那几步吗?装个包,改个配置文件,重启服务不就完了?

我也是这么想的,但实际用起来你会发现这些坑:

  1. 每台机器都要重复操作 - 装 samba、改 smb.conf、设置用户权限…
  2. 网络发现很麻烦 - 有时候在 macOS 上能看到,有时候又看不到
  3. 端口问题 - 有些网络环境只开了 445 端口,有些又是 139 端口
  4. 用户权限混乱 - 这台用 root,那台用 user,记不住哪个是哪个

最烦的是什么?就是当你着急要传个文件的时候,发现找不到共享文件夹,或者连接不上。那种感觉真的会让人抓狂。

我的解决思路

既然每台都要配,为什么不写个脚本一键搞定呢?

💡 核心想法

  • 用脚本自动化所有重复操作
  • 统一配置标准,避免每次都查文档
  • 加入网络发现功能,让 macOS 和 Windows 能自动找到
  • 支持多个共享目录,一次配置所有需求

不过说实话,一开始我也没想搞这么复杂。就想写个简单的 bash 脚本,装个 samba 包,改个配置文件就完事了。

但写着写着发现,如果要真正做到”一键配置”,还得考虑很多细节:

  • 不同发行版的包管理器不一样(apt vs yum)
  • 防火墙端口要开放
  • SELinux 权限问题
  • 网络发现服务的配置

所以最后就变成了下面这个”万能脚本”👇

通用 Linux 一键脚本

这个脚本主要针对 Ubuntu/Debian 系统(因为我的服务器大部分都是这个),如果你想用在 CentOS 上,只需要把 apt 换成 yum 就行。

来看脚本具体干了啥:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/bin/bash

SAMBA_CONFIG="/etc/samba/smb.conf"
AVAHI_CONFIG="/etc/avahi/services/samba.service"
AVAHI_DAEMON_CONF="/etc/avahi/avahi-daemon.conf"

# 颜色定义
GREEN="\e[32m"
RED="\e[31m"
RESET="\e[0m"

# 安装核心组件
echo -e "${GREEN}🔧 安装 Samba 和 Avahi...${RESET}"
sudo apt update
sudo apt install -y samba avahi-daemon avahi-utils

# 禁用 nmbd 服务
echo -e "${GREEN}🛑 禁用 nmbd 服务...${RESET}"
sudo systemctl stop nmbd 2>/dev/null
sudo systemctl disable nmbd 2>/dev/null

# 用户输入配置
read -p "请输入 NetBIOS 名称(用于网络发现): " NETBIOS_NAME

# 配置 Avahi 主机名
echo -e "${GREEN}🌐 配置 Avahi 主机名...${RESET}"
sudo sed -i "s/#host-name=.*/host-name=${NETBIOS_NAME}/g" $AVAHI_DAEMON_CONF
sudo sed -i "s/#publish-workstation=.*/publish-workstation=no/g" $AVAHI_DAEMON_CONF
echo -e "${GREEN}🌐 配置 Avahi 主机名...(done)${RESET}"

# 生成共享目录配置
declare -A SHARES
while true; do
read -p "请输入共享名称(输入 'done' 结束): " SHARE_NAME
[[ "$SHARE_NAME" == "done" ]] && break

read -p "请输入共享目录路径: " SHARE_PATH
read -p "请输入备注信息(可留空): " COMMENT

sudo mkdir -p "$SHARE_PATH"
SHARES["$SHARE_NAME"]="$SHARE_PATH|$COMMENT"
done

# 生成 Samba 配置
echo -e "${GREEN}🛠 生成 Samba 主配置...${RESET}"
sudo tee $SAMBA_CONFIG >/dev/null <<EOF
[global]
workgroup = WORKGROUP
netbios name = $NETBIOS_NAME
server string = $NETBIOS_NAME
disable netbios = yes
mdns name = mdns
wins support = yes
smb ports = 445
security = user
usershare owner only = false
public = yes
browseable = yes

EOF

# 添加共享目录配置
for SHARE_NAME in "${!SHARES[@]}"; do
IFS="|" read SHARE_PATH COMMENT <<< "${SHARES[$SHARE_NAME]}"
sudo tee -a $SAMBA_CONFIG >/dev/null <<EOF

[$SHARE_NAME]
comment = $COMMENT
path = $SHARE_PATH
public = yes
writable = yes
browseable = yes
create mask = 0775
directory mask = 0775
EOF
done

# 配置 Samba 用户
echo -e "${GREEN}🔑 设置 Samba 用户...${RESET}"
sudo mkdir -p /var/lib/samba/private/
sudo smbpasswd -a $USER

# 配置 Avahi 服务发现
echo -e "${GREEN}🌍 生成 Avahi 服务配置...${RESET}"
sudo tee $AVAHI_CONFIG >/dev/null <<EOF
<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards="yes">%h</name>
<service>
<type>_smb._tcp</type>
<port>445</port>
</service>
</service-group>
EOF

# 重启服务
echo -e "${GREEN}🔄 重启核心服务...${RESET}"
sudo systemctl restart smbd avahi-daemon

# 显示最终配置
echo -e "\n${GREEN}✅ 配置完成!${RESET}"
echo -e "📡 服务访问地址: smb://$(hostname -I | awk '{print $1}')"
echo -e "🔒 使用用户名 [$USER] 和您设置的密码访问"

脚本亮点解析

让我来解释一下这个脚本几个关键的设计思路:

1. 为什么禁用 nmbd 服务?

你可能注意到脚本里有这么一段:

1
2
sudo systemctl stop nmbd 2>/dev/null
sudo systemctl disable nmbd 2>/dev/null

说实话,我一开始也不知道为什么要禁用 nmbd。后来查了资料才发现:

nmbd 负责 NetBIOS 名称解析,这是传统的 Windows 网络发现方式。但在现代网络环境中,我们用的是 mDNS(Bonjour),所以 nmbd 不仅没用,还可能占用端口冲突。

而且,禁用 nmbd 后,Samba 会自动使用 mDNS 进行网络发现,这样在 macOS 的 Finder 里就能直接看到服务器了。

2. Avahi 配置的奥秘

这个配置很多人都会忽略:

1
2
sudo sed -i "s/#host-name=.*/host-name=${NETBIOS_NAME}/g" $AVAHI_DAEMON_CONF
sudo sed -i "s/#publish-workstation=.*/publish-workstation=no/g" $AVAHI_DAEMON_CONF

host-name 很好理解,就是设置网络中显示的名称。

publish-workstation=no 这个设置就很有意思了。如果不设为 no,你的服务器会在网络中广播为”工作站”,这可能会影响其他设备的网络发现。

我当时调试的时候就遇到了这个问题:在 Mac 上能看到服务器,但类型显示为”工作站”而不是”文件服务器”。查了半天才发现是这个配置的问题。

3. 为什么选择 mdns 而不是 wins?

看 Samba 配置的这两行:

1
2
mdns name = mdns
wins support = yes

这其实是做了个兼容性处理:

  • mdns 用于现代网络(macOS、Linux、Windows 10+)
  • wins 作为备用方案,兼容老设备

我家里的设备比较新,本来只用 mdns 就够了。但考虑到朋友有时候会用老电脑来访问,所以把 wins 也开着。

4. 权限设置的细节

这个配置很多人会搞错:

1
2
create mask = 0775
directory mask = 0775

为什么要设成 0775 而不是 0777?

  • 0775:创建的文件/目录,组内用户可以读写,其他人只能读取
  • 0777:所有人都能读写,不够安全

我家里的服务器都是我一个人用,但还是坚持最小权限原则。谁知道哪天会不会有设备被黑了呢?安全第一。

OpenWrt 软路由配置

说实话,OpenWrt 的 Samba 配置比我想象的要简单很多。

刚开始我以为 OpenWrt 跟普通 Linux 主机一样,得自己改一堆配置文件。后来发现 OpenWrt 有专门的 LuCI 界面和 opkg 包管理,走 Web 反而比命令行还轻松。

基础安装

1
2
3
4
5
6
7
8
9
opkg update
opkg install luci-app-samba4
opkg install uci-i18n-samba4-zh-cn

/etc/init.d/samba4 enable
/etc/init.d/samba4 start

smbpasswd -a root
# 输入密码

这里有个小坑:一定要安装中文语言包,不然在 Web 界面里看到的是英文,很多选项都搞不懂是干嘛的。

修改服务名称

OpenWrt 的网络发现服务名称默认是路由器型号,比如 “GL-iNet”。如果你想改成自定义的名字,需要手动改配置:

1
vim /etc/avahi/avahi-daemon.conf

找到 [server] 段,改成你想在 Finder / 网络邻居里显示的名字:

1
2
[server]
host-name=my-router

然后重启 avahi 服务:

1
2
/etc/init.d/avahi-daemon enable
/etc/init.d/avahi-daemon start

我的踩坑经历

当时我在 OpenWrt 上配完 Samba 后,在 Mac 上怎么都找不到这个服务。查了半天才发现:

OpenWrt 默认的防火墙规则会阻止 Samba 端口!

需要在防火墙设置里开放 445 和 139 端口,或者直接在 Web 界面的 Samba 设置里勾选”允许网络访问”。

还有一点,OpenWrt 的存储空间通常比较小,如果共享目录挂载在内部存储上,很快就会满。建议挂载到 USB 或者移动硬盘上。

调试常用命令

这些命令我在调试过程中经常用到,分享给大家:

macOS 网络发现调试

1
2
# 刷新 mDNS 缓存
sudo killall -HUP mDNSResponder

这个命令特别有用!有时候你明明配置好了,但在 Finder 里就是看不到服务,执行这个命令就出来了。

检查网络服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 检查 mDNS(Bonjour) 广播 SMB 服务的设备
dns-sd -B _smb._tcp

# AFP(Apple 文件共享协议)
dns-sd -B _afpovertcp._tcp

# FTP 服务器
dns-sd -B _ftp._tcp

# HTTP 服务器
dns-sd -B _http._tcp

# SSH 服务器
dns-sd -B _ssh._tcp

# NFS 服务器
dns-sd -B _nfs._tcp

这些命令用来检查网络中实际在广播什么服务。有时候你会发现某些服务在广播,但客户端就是连接不上,这就说明是客户端的问题而不是服务端的问题。

Linux 服务端调试

1
2
3
4
5
6
7
8
9
10
11
12
# 检查 Samba 服务状态
systemctl status smbd nmbd

# 检查端口监听
netstat -tlnp | grep :445
netstat -tlnp | grep :139

# 测试 Samba 配置
testparm

# 查看 Samba 连接
smbstatus

我的调试经验

有一次我在一台服务器上配置完 Samba 后,怎么都连不上。用上述命令一查,发现 445 端口根本没在监听。

原来是防火墙问题!我忘记了 Ubuntu 默认的 ufw 防火墙会阻止新端口。

1
2
3
sudo ufw allow 445/tcp
sudo ufw allow 139/tcp
sudo ufw reload

执行完这些命令,马上就能连上了。所以说,调试的时候一定要系统性地排查,不要瞎猜。

我的收获和感悟

通过这次折腾 Samba 的经历,我明白了几个道理:

1. 自动化脚本真的很有必要

刚开始我只是想写个简单的脚本,节省一点时间。但真正用起来才发现,标准化和一致性比单纯节省时间更重要。

家里的服务器多了之后,每台配置都不一样真的会很混乱。有了这个脚本后,所有服务器的 Samba 配置都是统一的,维护起来轻松很多。

2. 网络发现比想象中复杂

之前我以为 Samba 配置就是改个 smb.conf 文件,但深入了解后发现,网络发现服务(mDNS/NetBIOS)才是最难搞的部分。

不同操作系统的客户端对网络发现的支持也不一样:

  • macOS:主要靠 mDNS
  • Windows 10+:两者都支持
  • 老版本 Windows:主要靠 NetBIOS

所以我在脚本里选择两种都启用,确保最大兼容性。

3. 调试思路很重要

遇到问题的时候,不要慌,要有一套系统的调试思路:

  1. 先看服务状态 - 服务启动了吗?
  2. 再看端口监听 - 端口开放了吗?
  3. 然后看防火墙 - 防火墙放行了吗?
  4. 最后看网络发现 - 客户端能看到服务吗?

按这个顺序排查,基本上 99% 的问题都能找到原因。

4. 安全性不能忽视

虽然只是家里的局域网,但我还是坚持了一些安全实践:

  • 不用 777 权限
  • 禁用不必要的服务(nmbd)
  • 定期更新 Samba 版本

谁知道哪天会不会有设备被黑呢?做好基本的安全防护总是没错的。

最后想说的话

写完这个脚本后,我再也没有为 Samba 配置烦恼过。现在想在哪台服务器上开共享,直接 scp 过去跑一遍,几分钟就搞定,全家所有机器的 Samba 配置都是一个模子刻出来的。

这种一次编写、到处使用的感觉真的很爽。如果你也在为类似的问题烦恼,不妨也花一个晚上把它脚本化——这一个晚上,绝对比你未来每次”重新查文档、重新 apt install、重新改 smb.conf“省下的时间要少得多。

希望这篇文章能帮到和我一样被 Samba 折磨过的朋友们。


参考