前
在 Homelab 中折腾了一段时间后,我发现自己陷入了一个困境:随着设备数量的增加,管理 IP 地址变得越来越痛苦。
典型的场景是这样的:
– SSH 到某台服务器:ssh user@192.168.1.101,等等,101 是哪台机器来着?
– 访问某个服务:`http://192.168.2.88:8080`,这个 88 又是什么?
– 更糟糕的是,DHCP 租约过期后 IP 变了,所有的配置都要改一遍
我尝试过给每台设备绑定静态 IP,但这种方案有几个问题:
- IP 地址难以记住:20+ 台设备,每个都要记住对应的 IP
- 静态绑定不优雅:在路由器上一个个配置 DHCP 静态绑定很繁琐
- 缺乏灵活性:设备迁移到其他网络时需要重新配置
后来我发现了 mDNS(多播域名系统),它完美地解决了这些问题。配置完成后,我可以直接使用 server3.local、pfsense.local 这样的域名来访问设备,再也不用记 IP 地址了。
这篇文章记录了我在 OpenWrt + pfSense 双层路由环境下配置 mDNS 的完整过程,包括踩过的坑和解决方案。
我的网络环境
我的网络是两层路由结构:
– 一级路由:OpenWrt,家庭主路由器,网段 192.168.1.0/24
– 二级路由:pfSense,虚拟机网络路由器,网段 192.168.2.0/24
这样设置的目的是将虚拟机网络与主网络解耦,让 VM 可以独立运行并组成一个独立的集群。但这也带来了跨网段访问的问题,mDNS 的 reflector 功能正好可以解决这个问题。
路由配置篇
我的一级路由用的是 OpenWrt,二级路由用的是 pfSense。虽然系统不同,但配置思路是类似的。
核心组件是 Avahi,一个开源的 mDNS/DNS-SD 实现。OpenWrt 和 pfSense 都可以直接安装。
OpenWrt 安装配置
安装 Avahi
opkg update
opkg install avahi-daemon-service-ssh avahi-daemon-service-http
修改配置文件
编辑 /etc/avahi/avahi-daemon.conf:
[server]
use-ipv4=yes
use-ipv6=yes
check-response-ttl=no
use-iff-running=no
allow-interfaces=br-lan # 指定监听的网络接口
[publish]
publish-addresses=yes
publish-hinfo=yes
publish-workstation=no
publish-domain=yes
[reflector]
enable-reflector=yes # 关键:启用 reflector 功能,用于跨网段转发
reflect-ipv=no
[rlimits]
rlimit-core=0
rlimit-data=4194304
rlimit-fsize=0
rlimit-nofile=30
rlimit-stack=4194304
rlimit-nproc=3
关键配置说明
– allow-interfaces=br-lan:指定 Avahi 监听的网络接口
– enable-reflector=yes:启用 reflector 功能,这是实现跨网段 mDNS 的核心
参考:
pfSense 安装配置
安装插件
在 pfSense 的 Package Manager 中搜索并安装 avahi 插件。
关键问题:WAN 接口配置
这里我踩了个坑。pfSense 默认不允许在 WAN 接口启用 mDNS,这是出于安全考虑(如果 WAN 是公网,确实不应该暴露 mDNS)。
但在我的两层路由场景下,二级路由的 WAN 接口连接的是一级路由的 LAN,需要在 WAN 接口启用 mDNS 才能实现跨网段通信。
解决方法:修改插件源码
编辑 /usr/local/www/avahi_settings.php,找到并注释掉 WAN 过滤代码:
// vi /usr/local/www/avahi_settings.php
// 找到两处 wan 的过滤代码,注释掉:
// unset($available_interfaces['wan']);
修改后,在 Web 控制台就可以看到 WAN 选项了,同时选中 WAN 和 LAN 启用。
生成的配置文件
修改后 pfSense 会自动生成配置文件(位于 /usr/local/etc/avahi/avahi-daemon.conf):
这里需要注意:不推荐直接手动修改这个配置文件,因为它会被 GUI 覆盖。建议通过修改 PHP 源码让 GUI 支持 WAN 配置。
参考配置内容
# /usr/local/etc/avahi/avahi-daemon.conf
[server]
allow-interfaces=em0,em1 # WAN 和 LAN 接口
use-ipv4=yes
use-ipv6=no
[publish]
publish-addresses=yes
publish-domain=yes
[reflector]
enable-reflector=yes # 启用跨网段转发
可选:启用 D-Bus
某些情况下可能需要启用 D-Bus:
mkdir -p /var/run/dbus/
dbus-daemon --system
至此 pfSense 的配置就完成了。
防火墙配置
重要:mDNS 使用 UDP 5353 端口,需要在防火墙中开放此端口。
确保允许以下流量:
– 源:LAN 主机
– 目标:路由器本机(224.0.0.251,mDNS 组播地址)
– 端口:UDP 5353
具体配置方法因路由器而异,在 OpenWrt 或 pfSense 的防火墙规则中添加即可。
主机配置
路由器配置完成后,还需要配置各个主机才能使用 mDNS。我这里以 Ubuntu Server 为例。
设置 Hostname
首先给主机设置一个有意义的 hostname:
sudo hostnamectl set-hostname server3
之后就可以通过 server3.local 访问这台主机了。
配置网络为 DHCP
mDNS 的一大优势是不需要静态 IP,所以把网络配置改为 DHCP:
# 编辑 netplan 配置
vim /etc/netplan/00-installer-config.yaml
network:
ethernets:
ens34:
dhcp4: true
version: 2
# 应用配置
netplan apply
启用 systemd-resolved 的 mDNS 功能
Ubuntu 新版本使用 systemd-resolved 管理 DNS,需要在这里启用 mDNS:
# 编辑配置文件
vim /etc/systemd/resolved.conf
[Resolve]
MulticastDNS=yes
LLMNR=yes
或者用命令一键修改:
sed -i "s|#MulticastDNS=no|MulticastDNS=yes|g" /etc/systemd/resolved.conf
sed -i "s|#LLMNR=no|LLMNR=yes|g" /etc/systemd/resolved.conf
systemctl restart systemd-resolved
踩坑:Netplan 不支持 mDNS 配置
这里有个大坑。即使修改了 resolved.conf,mDNS 在网络接口上仍然是关闭的:
# 检查接口的 mDNS 状态
resolvectl mdns ens34
# 输出:Link 2 (ens34): no
# 手动启用
resolvectl mdns ens34 yes
但这个设置重启后会失效,因为 Netplan 不支持 mDNS 配置(相关 Bug,2019 年提出至今未修复)。
Netplan 会在 /run 目录下生成配置文件,优先级高于 /etc,导致手动修改无效。
解决方案:创建 systemd 服务
既然是开机自启动的问题,那就用 systemd 来解决:
创建 systemd 服务文件:
cat << EOF > /etc/systemd/system/user-set-mdns@.service
[Unit]
Description=Enable MulticastDNS on network interface
After=systemd-resolved.service
[Service]
ExecStart=resolvectl mdns %i yes
[Install]
WantedBy=multi-user.target
EOF
启用服务(替换 ens34 为你的网卡名称):
sudo systemctl enable user-set-mdns@ens34
sudo systemctl start user-set-mdns@ens34
sudo systemctl status user-set-mdns@ens34
至此,主机的 mDNS 配置就完成了,重启后也会自动生效。
方案二:使用 Avahi(适用于老系统)
如果你的系统没有使用 systemd-resolved(比如老版本的 Ubuntu 或 Debian),可以直接安装 Avahi:
sudo apt-get install avahi-daemon libnss-mdns libnss-mymachines
安装后 Avahi 会自动启动,无需额外配置。
验收测试
配置完成后,让我们测试一下效果。
基本测试
现在可以抛弃 IP 地址,直接使用 .local 域名访问设备:
ping server3.local
ping code-env.local
ping vm-proxy.local
ping pfsense.local
ping openwrt.local
实际使用场景
SSH 连接
# 以前
ssh user@192.168.2.101
# 现在
ssh user@server3.local
访问 Web 服务
# 以前
http://192.168.2.88:8080
# 现在
http://vm-proxy.local:8080
容器配置
# docker-compose.yml
services:
app:
environment:
- DATABASE_URL=postgresql://postgres@db-server.local:5432/mydb
跨网段测试
最重要的是测试跨网段访问,确认 reflector 功能正常工作:
# 从一级网络(192.168.1.x)访问二级网络设备
ping vm-server.local # 这台设备在 192.168.2.x 网段
# 从二级网络访问一级网络设备
ping openwrt.local # 这台设备在 192.168.1.x 网段
如果能 ping 通,说明 mDNS reflector 配置成功!
补充说明
二级路由的 IP 配置注意事项
后续重新部署时发现一个问题:如果 pfSense 二级路由使用静态 IP,会导致一级路由无法获取二级的 mDNS 记录。
解决方法
– 在一级路由(OpenWrt)上通过 DHCP 静态绑定给二级路由分配 IP
– 不要在二级路由上直接配置静态 IP
– 配置好后重启二级路由
OpenWrt 防火墙规则(命令行方式)
如果你习惯用命令行配置 OpenWrt 防火墙,可以使用以下命令:
uci -q delete firewall.mdns
uci set firewall.mdns="rule"
uci set firewall.mdns.name="Allow-mDNS"
uci set firewall.mdns.src="*"
uci set firewall.mdns.src_port="5353"
uci set firewall.mdns.dest_ip="224.0.0.251"
uci set firewall.mdns.dest_port="5353"
uci set firewall.mdns.proto="udp"
uci set firewall.mdns.target="ACCEPT"
uci commit firewall
/etc/init.d/firewall restart
后
配置完 mDNS 已经几个月了,现在回想起来,这是我在 Homelab 中做的最有价值的优化之一。
带来的改变
管理效率提升
– 不再需要维护一个 IP 地址清单
– 设备迁移或重启后不用担心 IP 变化
– 写配置文件时直接用域名,可读性大大提升
实际案例
最近我重装了一台服务器,以前的流程是:
1. 安装系统
2. 登录路由器配置静态 IP 绑定
3. 更新所有相关配置文件中的 IP
4. 重启依赖这台服务器的其他服务
现在的流程:
1. 安装系统
2. 设置 hostname
3. 完事
其他服务根本不需要改配置,因为它们用的是 server3.local 这样的域名,自动就能找到新的 IP。
一些建议
命名规范很重要
建议给设备起一个有意义的 hostname:
– nas.local 而不是 server1.local
– pve-node1.local 而不是 vm1.local
– k8s-master.local 而不是 ubuntu-001.local
好的命名可以让你半年后还记得这台设备是干什么的。
文档还是要有的
虽然不用记 IP 了,但建议维护一个简单的设备清单:
– 设备名称和 hostname
– 主要用途和运行的服务
– 重要配置文件位置
安全性考虑
mDNS 只适合内网使用,不要在公网暴露:
– 路由器 WAN 口不要启用 mDNS
– 如果有公网 IP,确保防火墙规则正确
– mDNS 流量不应该离开你的局域网
总结
mDNS 确实是 Homelab 的良药。它解决了 IP 地址管理的痛点,让网络配置更加灵活和优雅。虽然配置过程有一些坑(特别是 Netplan 的问题),但一旦配置好,体验提升是显著的。
如果你也在运营 Homelab,强烈建议试试 mDNS。配置时间不会超过一个下午,但带来的便利是长期的。
希望这篇文章能够帮助你顺利配置 mDNS,少走一些弯路。
参考链接