很多人第一次在 Ubuntu 上改网络配置,基本都会经历一次“至暗时刻”:ssh 远程登到一台服务器上,照着网上流传多年的老教程去改 /etc/network/interfaces,改了 IP、网关、DNS,顺手 reboot,然后连接就永久消失了。不是 DNS 不通,是整个网络栈都没起来,只能跑去机房或者用带外管理口救急。这个场景在 Ubuntu 17.10 之后几乎每天都会在各大技术社区上演——因为从那个版本开始,Ubuntu 默认的网络管理架构已经换成了 Netplan,配置文件从 interfaces 变成了 YAML 格式。现在聊 Ubuntu 的网络管理,核心就是三块:Netplan、路由和防火墙。
这篇是“跟韩工学 Ubuntu”第 5 章的第一篇,我们把网络管理里最基础也最容易翻车的三件事讲透:Netplan 到底怎么配、路由怎么加才不丢、防火墙怎么开才不会把自己锁在门外。
1. 为什么 Ubuntu 要跟“老方法”说再见:Netplan 的诞生背景
1.1 从 interfaces 到 Netplan:一次并不突兀的替换
很多老管理员对 /etc/network/interfaces 是有感情的。那个文件格式简单,auto eth0、iface eth0 inet static、address、netmask、gateway 一套下来,十几行就能搞定一张网卡。但这种配置方式的问题也很明显:它是针对“单机物理网卡”设计的,遇到网桥、VLAN、bond、Wi-Fi 这种复杂组合时,写法开始变得别扭;遇到云环境里动态创建和销毁接口的场景,基本无能为力。
Netplan 要解决的核心问题,是把网络配置抽象成“你想要的最终状态”,至于底层用 systemd-networkd 还是 NetworkManager 去实现,Netplan 不管。你只需要写一份 YAML 声明式配置,Netplan 负责把它翻译成后端的原生配置。这套思路在云原生大行其道的今天,是非常顺理成章的——你在声明配置,而不是在写一堆命令去“凑”出一个网络状态。
这里要澄清一个常见的误会:Netplan 不是网络服务,它本身不负责收发包。它更像一个翻译官和配置生成器。你执行 netplan apply 的时候,它根据 YAML 文件生成对应的 networkd 或 NetworkManager 配置,然后让后端服务重新加载。理解了这一层,很多“改了配置文件但没生效”“生成的配置和我写的不一样”的问题就都能想通了。
1.2 两个 renderer 到底怎么选
Netplan 支持两种后端渲染器:networkd 和 NetworkManager。这个选择直接影响你后续排查问题的方向。
networkd:systemd 体系下的网络管理服务,轻量、稳定、适合服务器。Ubuntu Server 默认走这个。NetworkManager:桌面环境常用的网络管理服务,更适合笔记本这种需要频繁切换 WiFi、插拔网线的场景。Ubuntu Desktop 默认走这个。
判断当前系统用哪个后端,可以直接看 /etc/netplan/ 下的 YAML 文件开头几行,一般会写 renderer: NetworkManager 或者 renderer: networkd。没有明确写 renderer 的情况下,Netplan 会按配置文件里的 network.version 和发行版默认值去判断。如果你的配置里既有网桥又用了 NetworkManager,注意 NetworkManager 对 bridge 的支持和 networkd 略有差异,部分高级路由策略(比如策略路由)建议直接走 networkd,后面的路由章节我会再细说。
这里还有一个乌班图新手特别容易踩的坑:/etc/netplan/ 目录下可能不止一个 YAML 文件,Netplan 会按文件名顺序合并它们。比如 00-installer-config.yaml、01-network-manager-all.yaml 可能在桌面版里同时存在,或者你自己又新建了一个 99-custom.yaml。文件多了之后,同名键后面的会覆盖前面的,所以如果你改了配置不生效,先确认是不是被另一个文件覆盖了。我的习惯是只保留一个文件,其他全部删掉或改名备份,避免这种隐性问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Netplan YAML 配置逐字段拆解:从零写一份能用的配置
2.1 最小可用配置:单网卡 DHCP
先看一个最简单的配置,Ubuntu Server 安装完默认生成的文件大概长这样:
yaml复制network:
version: 2
ethernets:
eth0:
dhcp4: true
这个配置的意思是:网络栈版本是 2,网卡 eth0 通过 DHCP 获取 IPv4 地址。保存后执行 sudo netplan apply 就能生效。
这里有几个 YAML 语法上的硬性注意事项:
- 缩进必须一致,用空格不用 tab,Netplan 对缩进的敏感程度比 Python 还夸张。
- 键名是大小写敏感的,
dhcp4不能写成DHCP4。 - 布尔值写
true/false,不要写yes/no。 - IP 地址必须带掩码长度,比如
192.168.1.10/24,不能只写192.168.1.10。
如果你是在远程服务器上操作,改完配置千万别直接 netplan apply,先用 sudo netplan try。这个命令会先试应用配置,如果 120 秒内你没有按回车确认,它会自动回滚到之前的配置。这是 Netplan 给远程维护留的一条命,后面排错章节我会细讲。
2.2 静态 IP、DNS 与多个地址的写法
服务器上最常见的需求就是配静态 IP。一个完整的配置长这样:
yaml复制network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: false
addresses:
- 192.168.1.100/24
- 192.168.1.101/24
routes:
- to: default
via: 192.168.1.1
nameservers:
addresses:
- 223.5.5.5
- 114.114.114.114
search:
- example.local
逐项解释一下:
addresses是一个列表,可以写多个 IP。很多人以为一个网卡只能有一个 IP,其实完全可以绑多个,这个列表就是干这个的。routes定义路由表,to: default表示默认路由,via是下一跳网关。这里替代了老配置里的gateway字段。nameservers.addresses配置 DNS 服务器,search配置域名搜索后缀,内网环境经常用到。
顺便说一个很多人念念不忘的 gateway4: true 字段。在 Netplan 的早期版本里,确实可以这么写:
yaml复制gateway4: 192.168.1.1
但这个字段从 Ubuntu 22.04 开始已经被标记为废弃,原因很简单:它只能配一个默认网关,一旦你有多网卡、多个网关的需求就完全不够用。统一的 routes 写法比一个独立的 gateway4 字段要灵活得多。新写的配置不要再用 gateway4,反正早晚会彻底移除,别给以后的自己留坑。
2.3 网桥与 VLAN:虚拟化场景绕不开的配置
如果你在 Ubuntu 上跑 KVM、LXD 或者 Docker 的 macvlan,网桥基本是绕不开的。Netplan 里配网桥非常直观:
yaml复制network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: false
bridges:
br0:
interfaces: [eth0]
addresses:
- 192.168.1.100/24
routes:
- to: default
via: 192.168.1.1
nameservers:
addresses:
- 223.5.5.5
parameters:
stp: true
forward-delay: 4
这里的关键是:物理网卡 eth0 只做桥接端口,不配置 IP;IP 和网关都放到 br0 上。新手最容易犯的错是把 eth0 也配上 IP,结果桥一建起来流量就乱套了。
本身不带 IP 的桥接物理口,接口名尽量用 interfaces: [eth0] 的列表形式,不要用 interfaces: eth0,虽然 Netplan 偶尔也能接受,但规范的列表写法能避免一部分解析歧义。
VLAN 的配置也类似,在虚拟化环境下经常要用到:
yaml复制network:
version: 2
ethernets:
eth0:
dhcp4: false
vlans:
vlan10:
id: 10
link: eth0
addresses:
- 172.16.10.2/24
注意这个配置要求物理网卡 eth0 本身是 up 的状态,但它不需要 IP。VLAN 接口名可以自定义,link 指定它挂在哪个物理接口上。如果你发现 VLAN 不通,先用 ip link show vlan10 确认接口状态是不是 UP,再排查交换机侧的 VLAN 配置,不要一上来就怀疑 Ubuntu。
2.4 netplan try、apply、generate 和 get:别把四个命令搞混
Netplan 的命令不多,但很多人分不清它们各自到底干了什么。
sudo netplan generate:只把 YAML 翻译成后端的配置文件(比如 networkd 的.network文件),不应用,不重启网络。这个命令适合检查你的 YAML 语法是不是合法,以及 Netplan 能不能正确解析。sudo netplan apply:把配置真正应用到系统,会触发网络服务重载。这是最常用的命令,但也有一定风险——如果你把 IP 配错了,远程连接大概率当场断掉。sudo netplan try:先 apply,然后给你 120 秒确认时间,超时或按回车以外的操作自动回滚。远程操作必须养成用 try 的习惯。sudo netplan get:查看当前生效的配置,相当于“反编译”当前状态的 YAML。
这里分享一个平时排查特别好用的小技巧:先用 sudo netplan generate 检查语法,如果没问题会静默通过;如果 YAML 写错了,它会直接提示错误行号。确认语法没问题后,再用 netplan try 或者谨慎地 netplan apply。另外,如果你改了文件但想看看 Netplan 到底生成了什么,可以在 /run/systemd/network/ 目录下查看 networkd 实际加载的配置,那里是 Netplan 翻译后的产物,很多“为什么我写的没生效”的答案都在这里。
3. 路由实战:默认网关、静态路由与策略路由
3.1 默认网关的坑:为什么双网卡只有一个默认路由能活
路由,说白了就是数据包出门的路线表。最容易出事的场景是服务器有多个网卡,比如一张网卡走办公网、一张网卡走业务网。很多人的第一反应是给两张网卡各配一个默认网关,结果发现只有一张网卡能通,另一张怎么都不行。
这不是 Ubuntu 的 bug,也不是 Netplan 的毛病。Linux 内核的路由表里默认路由只能有一条,或者说,相同前缀的路由只能有一条被选为“最优”。当你给 eth0 配了 to: default via: 192.168.1.1,又给 eth1 配了 to: default via: 10.0.0.1,内核会保留 metric(路由优先级)更小的那条,另一条大概率不会生效,或者两条反复争夺导致流量走向不稳定。
正确的做法是:分清哪个是主出口,哪个是只访问特定网段的出口。主出口用默认路由,其他出口用静态路由。比如服务器有 eth0(192.168.1.100/24)和 eth1(10.0.0.100/24),业务网段是 10.10.0.0/16,想要访问业务网段时走 eth1,其余流量都走 eth0:
yaml复制network:
version: 2
renderer: networkd
ethernets:
eth0:
addresses:
- 192.168.1.100/24
routes:
- to: default
via: 192.168.1.1
eth1:
addresses:
- 10.0.0.100/24
routes:
- to: 10.10.0.0/16
via: 10.0.0.1
这段配置里,10.10.0.0/16 的流量会被精确匹配走 10.0.0.1,其他所有流量走去 192.168.1.1。路由匹配的优先级是“最长前缀匹配”,也就是说目标地址能匹配上的前缀越长越优先,跟配置顺序无关。所以即使默认路由写在前面,10.10.0.0/16 的精确路由也不会被覆盖。
3.2 策略路由:多出口场景的进阶玩法
上面那种“一个默认路由 + 几条静态路由”的方案,能解决大部分普通双网卡场景,但遇到更复杂的策略就力不从心了。比如:来自 192.168.1.0/24 的流量走 eth0,来自 10.0.0.0/24 的流量走 eth1,更进一步要求:ping 服务器 eth1 的 IP,回包还必须从 eth1 走。
这种“按来源决定走向”的需求,静态路由是做不到的,必须上 PBR(Policy Based Routing,策略路由)。PBR 的思路是维护多张独立的路由表,然后用规则把流量分到不同的表里。
Netplan 配置策略路由的写法如下:
yaml复制network:
version: 2
renderer: networkd
ethernets:
eth0:
addresses:
- 192.168.1.100/24
routes:
- to: default
via: 192.168.1.1
table: 100
routing-policy:
- from: 192.168.1.0/24
table: 100
这里的关键字有 table 和 routing-policy:把默认路由放进编号为 100 的路由表,再用规则把所有源地址为 192.168.1.0/24 的流量引导到这张表。你需要在 /etc/iproute2/rt_tables 里给编号 100 起个名字(比如 office),虽然不起名字直接用数字也能跑,但命名后 ip route show table office 会更好看、更好排错。
验证策略路由是否生效,用这两条命令:
bash复制ip rule show
ip route show table 100
第一行看规则,第二行看指定路由表的内容。如果你在 ip rule show 里看到了 from 192.168.1.0/24 lookup 100,并且 table 100 里有正确的默认路由,那策略路由基本就成了。
3.3 路由不生效怎么办:先查这四样
路由配置写好后,不要急着一路 ping 下去,按顺序检查这四个地方:
第一,ip route show 看主路由表。确认默认路由和静态路由确实写进去了。如果 Netplan 配置里有但这里没有,大概率是 netplan apply 没执行成功,或者配置被其他文件覆盖了。
第二,ip rule show 看策略路由规则。如果你配了 routing-policy,这里必须能看到对应的规则。没有的话,检查 YAML 里是不是把 routing-policy 写错了位置,它和 routes 是平级关系,都在 ethernets.eth0 下面。
第三,ip route get <目标IP> 做路线诊断。这条命令是排查路由问题的利器,它会告诉你从本机去往某个 IP 实际走哪张表、哪个接口、哪个网关。比如你怀疑去 10.10.0.0/16 的路由不对,直接 ip route get 10.10.0.1,如果显示走了错误接口,那问题就在路由匹配优先级上。
第四,ping 和 traceroute 做链路验证。注意 ping 通了不代表路由对,ping 不通也不代表路由错,可能是防火墙在拦 ICMP。先确认到网关的通达性,再确认到远端网络,逐跳排查。
4. 防火墙基础:ufw 先上手,nftables 再进阶
4.1 ufw:五条命令搞定 80% 的规则
Ubuntu 的防火墙体系,普通用户最常接触的是 ufw,全称 Uncomplicated Firewall,翻译过来就是“不复杂的防火墙”。它的定位就是让不熟悉 iptables 语法的人也能快速配置基本规则。
常用命令就这么几条:
bash复制sudo ufw enable
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 192.168.1.0/24 to any port 22
sudo ufw status verbose
这套命令干的事很朴素:启用防火墙,默认拒绝所有入站,默认放行所有出站,然后按需放行 SSH、HTTP、HTTPS。如果你刚配好一台新服务器,我建议先执行 sudo ufw allow 22/tcp 再执行 sudo ufw enable,这个顺序至关重要——先把 SSH 放行规则写好再开防火墙,不然一条 default deny incoming 就可能把你自己锁在外面。
这里要专门提一下“限制 SSH 爆破”的规则:
bash复制sudo ufw limit ssh
limit 会对符合条件的连接做速率限制,超过阈值直接拒绝。对于暴露在公网上的服务器,这条规则比单纯 allow 22/tcp 安全得多。
4.2 ufw 的局限:不是所有场景都适合用它
ufw 虽然简单,但它是基于 iptables 的前端封装,能力上限很明显。举几个场景你就明白了:
第一,你没法像 Windows 防火墙那样直接“屏蔽某款应用的联网行为”,比如网上经常有人问“怎么屏蔽某个 exe 联网”,Linux 上没有这个玩法。Linux 防火墙的工作对象是 IP、端口、协议,不是进程名。想限制某个程序联网,得用其他手段,比如 firejail、按用户组路由等,这已经超出了防火墙本身的范畴。
第二,复杂的地址转换(NAT)、端口转发、流量标记等高级功能,ufw 提供不了,或者写起来特别别扭。这些场景你需要直接面对 nftables。
第三,两个设备之间网络不通,一方怀疑是防火墙拦了,另一方法确认“我关了防火墙啊”。这种问题在 ufw 里尤其常见——你执行了 sudo ufw disable,但系统里同时还有 nftables 的规则在生效。ufw disable 只是关闭 ufw 自己写入的规则,并不会清空 nftables 里已有的规则集。遇到这种“两边防火墙都关了还不通”的情况,直接列出当前 nftables 的规则集看个明白。
4.3 nftables:现代 Linux 防火墙的正确打开方式
从 Ubuntu 20.04 开始,iptables 底层已经换成了 nftables 框架。iptables 命令虽然还能用,但它现在只是 nftables 的兼容层。新写的规则,我建议直接用 nft 命令。
nftables 的规则结构是 表(table)→ 链(chain)→ 规则(rule),相比 iptables 的大杂烩,它的组织更清晰。一个最简单的放行 SSH 规则集长这样:
bash复制sudo nft add table inet myfilter
sudo nft add chain inet myfilter input { type filter hook input priority 0\; policy drop\; }
sudo nft add rule inet myfilter input ct state established,related accept
sudo nft add rule inet myfilter input iif lo accept
sudo nft add rule inet myfilter input tcp dport 22 accept
sudo nft list ruleset
这段命令创建了一个叫 myfilter 的表,一个挂载在 input 钩子上的链,策略默认丢弃,然后依次放行已建立的连接、回环接口流量和 SSH 端口。
如果你之前只接触过 iptables,注意 nft 的几个习惯变化:链名可以自定义,不用像 iptables 那样固定叫 INPUT;数据类型和匹配条件写法更规整,比如 tcp dport 22 不再需要 --dport 22;所有规则可以一条 nft list ruleset 看全,非常直观。
4.4 规则持久化:重启之后怎么不丢
不管是用 ufw 还是 nft,规则默认都存在内存里,重启就没了。配置持久化有三条路:
- ufw 用户:
sudo ufw enable后,规则由 ufw 自己管理,重启会自动加载,不需要额外处理。 - nftables 用户:官方推荐的方法是先把规则导出到文件,再在 systemd 里启用恢复服务。
bash复制sudo nft list ruleset > /etc/nftables.conf
sudo systemctl enable nftables
sudo systemctl restart nftables
- 混合场景:如果你既有 ufw 又手动加了几条 nft 规则,重启后手动加的那部分会丢。这时候要么全交给 ufw,要么全交给 nftables,别两套混着管理,不然排查起来非常痛苦。
我个人的建议是:对外提供服务的生产服务器,规则不复杂就全部走 ufw;如果涉及到端口转发、NAT、多网卡流量标记这些高级需求,直接学 nftables,一步到位。ufw 目前无法覆盖的场景,终究还是得到 nftables 去解决,晚学不如早学。
5. 排错纪实:改配置断连、路由失效、防火墙误伤的真实翻车现场
5.1 改完配置 SSH 瞬间断连:netplan try 的保命用法
这个场景我见过太多次,自己也经历过。远程连着一台 Ubuntu 服务器,改完 Netplan 配置,手一快敲了 sudo netplan apply,回车之后 SSH 立刻卡住,然后断开。因为是远程维护,没有显示器没有串口,只能让机房同事帮忙重启,运气好旁边的 IPMI 还能用,运气不好就得跑一趟。
正确姿势永远是:
bash复制sudo netplan try
它会打印类似这样的话:配置已应用,如果要回滚,请在 120 秒内按回车。这个等待时间里,你开一个新的 SSH 连接测试,如果连不上,不要动任何键,等超时自动回滚;如果连得上,再回来按回车确认。
这条命令还有个细节:默认等待 120 秒,但你可以指定等待时间,比如 sudo netplan try --timeout=30。我一般保留默认,因为测试需要时间,120 秒足够开一个新终端做一次完整验证了。
如果你连到一台机器上发现它已经断网了,而你既没有控制台也没带外管理,可以用 U 盘启动系统,挂载原有磁盘,然后去改 /etc/netplan/ 下的 YAML 文件把它改回可用配置。这是最后的应急手段,操作起来不复杂,就是需要动手拆机器或者找物理访问途径。
5.2 路由表里有条目但就是不生效:一个典型的双网卡迷失案
有一次帮朋友排查一台双网卡 Ubuntu 服务器,现象是 ip route show 里明明有一条去往 10.10.0.0/16 的静态路由,但 ping 10.10.0.1 就是不通。一开始我也以为是对端防火墙问题,查了一圈不是。
最后用 ip route get 10.10.0.1 一看,路由走的根本不是我以为的那个网卡,而是默认路由的出口。原因出在路由表的“主表”和“策略路由规则”的配合上——在默认的 ip rule 规则里,所有流量会先查 local 表(优先级 0),然后查 main 表(优先级 32766)。如果你把静态路由配到了自建的表里,但没有对应的规则让流量去查那张表,那条路由等于白配。
所以排查这类问题的黄金顺序是:先 ip route get 看实际选路结果,再 ip rule show 看规则是否引导到了正确的表,最后再回头看 netplan 文件里的 routes 和 routing-policy 是否配对。很多时候不是“路由不存在”,而是“路由在错误的表里,或者根本没人去查那张表”。
5.3 防火墙把正常流量拦了:从现象到日志的完整链路
防火墙导致的“网络不通”,是另一种高频翻车点。最典型的场景是两台设备直连,一边怎么都 ping 不通另一边,两边都打开防火墙看了一眼说“关了呀,没问题”。这种我一般直接上三条命令定位:
bash复制sudo ufw status verbose
sudo nft list ruleset
sudo dmesg | grep -i drop
前两条看防火墙规则,第三条是杀手锏——如果 Linux 内核的 nftables 丢包,很多时候会在内核日志里留下痕迹。dmesg 里出现大量 drop 记录,基本就坐实了是防火墙在拦。
还有一个更隐蔽的场景:两台设备建立连接时总提示“网络不一致”,要求确保防火墙放行。这种问题十有八九不是出在规则本身,而是出在“默认策略和回程流量”上。比如你只放行了入站的 22 端口,但没放行已建立的连接和回程的流量,那 TCP 握手都完不成。nftables 里明确需要一条 ct state established,related accept 才能让回程流量正常通过,ufw 默认会处理好这些,但你如果绕过 ufw 直接在 nft 层加规则就很容易漏掉。
5.4 把恢复动作练成肌肉记忆
防火墙和路由操作有个共性:一旦出错,最需要的是快速恢复,而不是慢慢研究。我和身边同事的习惯是,所有高风险操作之前想清楚退路:
- Netplan 操作前确认服务器有控制台或者 IPMI 可用,没有的话老老实实
netplan try。 - 防火墙操作前先把允许 SSH 的规则写进去,再开全局默认拒绝,顺序错了宁可不做。
- 改完路由后不要急着关当前 SSH 窗口,而是新开一个窗口验证,旧的保持会话不断。
这几个习惯听着简单,但真到半夜三点维护生产服务器的时候就显价值了。网络管理这个领域,配置写得漂亮的人很多,但半夜能安全地把配置回滚回来的,才是真正的老手。
我在实际使用中发现一个很有意思的点:接触 Netplan 时间越长,越觉得它那套“声明式配置”的思路是对的。虽然 YAML 的缩进偶尔让人抓狂,虽然 apply 和 try 的区别一开始容易混淆,但相比在 /etc/network/interfaces 里手工维护一堆互相依赖的配置,Netplan 起码让你能一眼看出这张网卡的完整状态。下一篇文章我会继续拆解第 5 章的 002 篇,重点讲 NetworkManager 和 networkd 共存时的处理思路,以及更深入的网络诊断工具用法,到时候我们再接着聊。
