1. 为什么固定 IP 这件事,远比想象中更容易翻车
很多人第一次在 Ubuntu 上配固定 IP,都是被逼的。要么是家里跑了个小服务,路由器每次重启后地址就变,手机上的书签全失效;要么是公司内网里要连一台开发机,DHCP 分配的地址三天两头换,SSH 配置改到崩溃;再或者是搭了个本地文件共享,结果同事的电脑永远连不上,最后发现是 IP 又漂了。固定 IP 看起来是个特别小的需求,但真正动手的时候,你会发现 Ubuntu 上这件事的坑比想象中多得多——尤其是从桌面版换到服务器版、从旧版本换到新版本之后,网上搜到的教程一半是过时的,另一半是抄来抄去的,照着敲完命令,网络直接断了,连回滚的机会都没有。
我自己就吃过这个亏。早些年在一台远程开发机上改网络配置,改完netplan apply一执行,SSH 当场掉线,人又不在机器旁边,只能等第二天到现场接显示器救回来。从那以后我养成了一个习惯:改网络配置之前,先把回滚方案准备好,并且尽量在本地控制台或者带外管理通道下操作。这个教训值不少钱,后面会反复提到。
这篇内容面向的是需要在 Ubuntu 上把动态地址改成静态地址的开发者、运维人员,以及在家里折腾小服务器的爱好者。不管你是用桌面版还是服务器版,是 Ubuntu 18.04 之后的 Netplan 体系,还是更老的 ifupdown 体系,我都会把原理、步骤、验证方法和踩坑经验讲清楚。核心关键词就几个:Ubuntu 固定 IP、Netplan 配置、静态地址、网关与 DNS、网络验证。读完你应该能做到:不看教程也能自己写出正确的配置文件,出了问题知道从哪一层开始排查,而不是盲目重启网络服务。
需要先说明一点:Ubuntu 从 17.10 开始默认用Netplan管理网络,配置文件放在/etc/netplan/目录下,格式是 YAML。而更早的版本用的是/etc/network/interfaces。这两个体系完全不同,混用会出问题。下面主要围绕 Netplan 展开,最后会单独说老版本的兼容做法。
2. 动手之前必须搞清楚的几个网络概念
2.1 固定 IP 到底"固定"了哪几样东西
很多人以为固定 IP 就是填一个地址进去,其实一个能正常上网的静态配置至少包含四样东西:IP 地址、子网掩码(或 CIDR 前缀)、默认网关、DNS 服务器。少任何一样,表现都不一样:只填 IP 不填网关,局域网内能通但出不了外网;不填 DNS,能 ping 通 IP 但域名解析全挂;子网掩码填错,可能连网关都 ping 不到。这四样是一个整体,配置的时候要一起想清楚。
举个具体的例子。假设你的局域网网段是192.168.1.0/24,路由器(网关)地址是192.168.1.1,你想给机器固定成192.168.1.50。那么配置里应该体现为:地址192.168.1.50/24,网关192.168.1.1,DNS 可以填路由器地址,也可以填公共 DNS。这里的/24就是子网掩码255.255.255.0的另一种写法,表示前三段是网络位,最后一段是主机位。这个换算关系一定要熟,因为 Netplan 用的是 CIDR 写法,不认点分十进制的掩码。
2.2 选哪个地址才不会被路由器"抢走"
固定 IP 有一个隐藏的坑:你选的地址可能和路由器的 DHCP 地址池冲突。比如路由器 DHCP 池是192.168.1.100到192.168.1.200,你偏偏把机器固定成192.168.1.150,那么某天路由器把这个地址分配给别的设备,两边就撞车了,表现为网络时通时断,非常难查。正确做法是把静态地址选在 DHCP 池之外,比如池子从 100 开始,你就用 50 以下的地址;或者干脆在路由器上做地址保留(DHCP 静态绑定),让路由器永远把某个地址分给这台机器的 MAC。
我个人的习惯是:静态地址统一规划在一个小段里,比如 2 到 99,并且在本子上或者文档里记下来哪台机器用了哪个地址。设备一多,不记录必然乱。这个习惯看起来土,但比任何花哨的 IPAM 工具都管用,尤其是在家庭或小团队环境里。
2.3 Netplan 和传统配置的本质区别
传统interfaces文件是"描述式"的,你写什么它就是什么,改完重启网络服务就生效。Netplan 则是"声明式"的,你写的是期望状态,由它去调用底层的渲染器(通常是 systemd-networkd 或 NetworkManager)来落地。这个设计带来的直接影响是:Netplan 配置文件对缩进极其敏感,YAML 用空格缩进,两个空格是一层,用 Tab 会直接报错;而且改完之后必须执行netplan apply才会生效,光保存文件没用。
还有一个容易忽略的点:Netplan 目录下可能有多个 YAML 文件,比如安装系统时自动生成的50-cloud-init.yaml,加上你手动创建的01-netcfg.yaml。这些文件会按文件名字典序合并,数字小的先加载,后面的覆盖前面的。所以如果你在50-cloud-init.yaml里改了配置,但系统里还有个99-something.yaml也定义了同一块网卡,最终生效的可能是后者。排查"改了没生效"的问题时,第一件事就是ls /etc/netplan/看看有几个文件。
3. 从零写一份能用的 Netplan 配置
3.1 先确认网卡名字,别凭感觉写
配置之前必须先知道网卡的真实名字。执行:
ip link show输出里会列出所有网络接口,比如lo(回环)、enp3s0、ens33、wlp2s0(无线)等。新版 Ubuntu 的网卡命名规则是"可预测命名",名字可能是enp0s3、enp2s0f0这种,和老教程里的eth0完全不一样。如果你照着老教程写eth0,而机器上根本没有这个接口,netplan apply会报错或者静默不生效。
另一个确认方式是:
ip addr show看哪个接口有inet地址、状态是UP,那个就是你在用的网卡。无线网卡的名字通常以wl开头,有线以en开头。记下这个名字,后面所有配置都要用它。
3.2 一份完整的静态地址配置长什么样
假设网卡名是enp3s0,要固定成192.168.1.50/24,网关192.168.1.1,DNS 用192.168.1.1和223.5.5.5。配置文件可以这样写,保存为/etc/netplan/01-netcfg.yaml:
network: version: 2 renderer: networkd ethernets: enp3s0: dhcp4: no addresses: - 192.168.1.50/24 routes: - to: default via: 192.168.1.1 nameservers: addresses: [192.168.1.1, 223.5.5.5]逐行解释一下为什么这么写。version: 2是 Netplan 的配置版本,现在基本都用 2。renderer: networkd指定底层用 systemd-networkd 渲染,服务器版默认就是它;桌面版可能用 NetworkManager,写NetworkManager也行,但服务器上建议保持 networkd。dhcp4: no明确关掉 IPv4 的 DHCP,不写这一行有时会残留 DHCP 行为。addresses是地址列表,CIDR 写法。routes里to: default表示默认路由,via是网关地址——注意老版本 Netplan 用的是gateway4字段,新版本已经废弃,继续用会报警告甚至不生效,这是最常见的版本兼容坑之一。nameservers里填 DNS,可以填多个,按顺序使用。
写文件的时候有个硬性要求:只能用空格缩进,绝对不能用 Tab。YAML 对 Tab 零容忍,一个 Tab 就能让整个文件解析失败。建议用nano或者vim时先确认没有开启自动 Tab 转换。
3.3 权限和语法检查,别急着 apply
Netplan 配置文件涉及网络底层,权限必须收紧。官方建议的权限是:
sudo chmod 600 /etc/netplan/01-netcfg.yaml权限太宽(比如 644)时,netplan apply会给出警告,虽然不一定阻止生效,但属于隐患。改完权限后,先做语法检查:
sudo netplan try这个命令会临时应用配置,并给你 120 秒确认时间。如果配置有问题导致网络断开,时间到了会自动回滚;如果确认没问题,按回车正式生效。这是整个流程里最有价值的一个命令,尤其是远程操作的时候,它相当于给你留了一条退路。相比之下,直接netplan apply是没有自动回滚的,配错了就只能靠控制台救。
提示:
netplan try在部分精简系统或容器环境里可能不可用,这时候退而求其次,先在本地控制台操作,或者提前准备好一条能恢复 DHCP 的命令。
4. 应用配置之后,怎么验证真的生效了
4.1 三层验证法:地址、路由、DNS
配置应用后不要只看一个ip addr就完事,要分三层验证。第一层看地址:
ip addr show enp3s0确认inet后面是你设置的地址和前缀,比如192.168.1.50/24。如果还是 DHCP 分配的旧地址,说明配置没生效,回去检查文件名、网卡名和缩进。
第二层看路由:
ip route show输出里应该有default via 192.168.1.1 dev enp3s0这一行。没有默认路由,就出不了外网。如果这行缺失,多半是routes段写错了,或者用了废弃的gateway4而新版本不认。
第三层看 DNS:
resolvectl status或者老一点的系统用systemd-resolve --status。看当前网卡对应的 DNS 服务器是不是你配置的那几个。DNS 没生效的典型表现是ping 223.5.5.5能通,但ping www.example.com报"无法解析"。
三层都过了,再做一个端到端测试:
ping -c 4 192.168.1.1 ping -c 4 223.5.5.5 ping -c 4 www.example.com三个分别对应网关连通、外网 IP 连通、域名解析。哪一步断,问题就定位在哪一层,比盲目重启服务高效得多。
4.2 重启之后还生效吗
很多人配置完当场是好的,重启一次又变回 DHCP 了。原因通常是:配置文件放错了目录,或者被 cloud-init 覆盖了。云环境里的 Ubuntu 镜像经常带50-cloud-init.yaml,cloud-init 在每次启动时可能重新生成网络配置,把你手写的文件覆盖掉。判断方法:
ls -la /etc/netplan/ cat /etc/netplan/50-cloud-init.yaml如果这个文件里也有网络定义,而且内容和你写的不一致,就要处理它。常见做法是在/etc/cloud/cloud.cfg.d/下放一个配置禁用 cloud-init 的网络管理,或者直接修改 cloud-init 的源配置。这一步不做,重启后配置丢失是必然的,而且现象很迷惑——明明刚才还好好的。
验证重启是否生效,最稳妥的方式就是真的重启一次:
sudo reboot重启后重新跑一遍 4.1 的三层验证。别嫌麻烦,这一步能提前暴露 90% 的"配置不持久"问题。
5. 那些年我踩过的坑和对应的排查链路
5.1 改完配置 SSH 直接断,人不在现场怎么办
这是最经典的翻车场景。远程 SSH 到一台机器上改网络,netplan apply一敲,连接立刻断开,因为 IP 变了,原来的 SSH 会话自然失效。如果新 IP 又没配通,就彻底失联了。我的处理链路是这样的:优先用netplan try而不是apply,它自带回滚;如果必须用apply,提前开一个tmux或screen会话,并且准备好一条"恢复 DHCP"的命令,比如把配置文件改回dhcp4: yes再 apply。更稳妥的是通过带外管理(比如服务器的管理口、虚拟化平台的控制台)操作,这样即使网络全断也能进去。
还有一个细节:改 IP 之前先确认新地址在局域网里没有被占用。用arping探一下:
arping -I enp3s0 192.168.1.50 -c 3有回应说明这个地址已经被别的设备用了,换一个。这个检查只要几秒钟,能避免后面一堆莫名其妙的冲突问题。
5.2 "改了没生效"的完整排查顺序
遇到配置不生效,不要东改西改,按固定顺序排查效率最高。我总结的顺序是:
| 排查步骤 | 检查内容 | 常见问题 |
|---|---|---|
| 1 | ls /etc/netplan/ | 有多个文件互相覆盖 |
| 2 | 文件权限和缩进 | 用了 Tab、权限过宽 |
| 3 | 网卡名是否匹配 | 写了eth0但实际是enp3s0 |
| 4 | 字段是否过时 | 用了废弃的gateway4 |
| 5 | netplan apply的报错输出 | 语法错误、渲染器冲突 |
| 6 | 底层渲染器状态 | networkd 和 NetworkManager 打架 |
第 6 步值得展开说。Ubuntu 桌面版默认用 NetworkManager 管理网络,如果你在 Netplan 里指定renderer: networkd,可能出现两套系统同时想管一块网卡的情况,表现为配置时好时坏。桌面版建议统一用NetworkManager作为渲染器,或者干脆用图形界面的网络设置来配静态地址,底层它也是写 Netplan 文件,但不容易写错格式。
5.3 无线网卡配静态地址的特殊处理
有线网卡的配置相对直接,无线网卡要多考虑一层:WiFi 的 SSID 和密码。Netplan 里无线配置大概长这样:
network: version: 2 wifis: wlp2s0: dhcp4: no addresses: [192.168.1.60/24] routes: - to: default via: 192.168.1.1 nameservers: addresses: [192.168.1.1] access-points: "你的WiFi名称": password: "你的密码"这里最容易错的是access-points的缩进层级,它和addresses是平级的,都在网卡名下面。另外 WiFi 名称里有空格或特殊字符时要加引号。无线配静态地址的实际体验不如有线稳定,如果机器同时有有线和无线,建议只给有线配静态,无线保持 DHCP,避免路由表里出现两条默认路由互相干扰。
6. 老版本 Ubuntu 和特殊场景的兼容做法
6.1 还在用 interfaces 文件的系统
Ubuntu 16.04 及更早版本用/etc/network/interfaces,配置长这样:
auto enp3s0 iface enp3s0 inet static address 192.168.1.50 netmask 255.255.255.0 gateway 192.168.1.1 dns-nameservers 192.168.1.1 223.5.5.5改完执行sudo systemctl restart networking生效。注意这里的掩码是点分十进制写法,和 Netplan 的 CIDR 不同。如果你的系统里同时存在interfaces和 Netplan 目录,说明是升级过来的混合环境,以 Netplan 为准,interfaces可能已经不被读取了。判断当前用的是哪套,看systemctl status systemd-networkd和systemctl status networking哪个是 active 状态。
6.2 容器和虚拟机里的注意事项
在虚拟机里配静态地址,除了系统内的配置,还要注意虚拟化平台本身的网络模式。NAT 模式下,虚拟机的网关通常是平台指定的地址(比如192.168.x.1或10.0.x.1),不能随便填宿主机的地址;桥接模式下才和物理局域网平级。容器环境更特殊,很多容器默认不跑完整的网络管理服务,Netplan 可能根本不生效,这时候静态地址要在容器编排层或者启动参数里指定,而不是改容器内的配置文件。
我遇到过一种情况:在虚拟机里按教程配好静态地址,ip addr显示正确,但就是上不了网。查了半天发现虚拟化平台的 NAT 网关地址和教程里写的不一样,改对网关后立刻正常。所以配静态地址前,先用 DHCP 模式跑一次ip route,把真实的网关地址记下来,这是最可靠的参照。
6.3 多网卡和多地址的配置思路
一台机器有两块网卡时,要明确哪块走外网、哪块走内网。默认路由只能有一条(或者用优先级区分),否则会出现"流量从错误的网卡出去"的问题。Netplan 里可以给路由加metric来指定优先级,数值小的优先:
routes: - to: default via: 192.168.1.1 metric: 100同一块网卡配多个地址也很常见,addresses下面列多个即可,比如同时挂一个内网地址和一个管理地址。这种配置在服务器上很实用,但要确保每个地址所在的网段都有对应的路由,不然会出现"地址配了但 ping 不通"的怪现象。
7. 一套可以反复用的操作清单
把上面的内容压缩成一套可执行的动作,每次配静态地址照着走,基本不会翻车。第一步,用ip link确认网卡名,用 DHCP 状态下的ip route记下真实网关。第二步,选一个 DHCP 池之外的地址,用arping确认没被占用。第三步,写/etc/netplan/01-netcfg.yaml,注意缩进用空格、字段用新版routes而不是gateway4。第四步,chmod 600收紧权限,netplan try试运行并确认。第五步,三层验证地址、路由、DNS,再做端到端 ping 测试。第六步,重启一次确认持久化,检查有没有 cloud-init 之类的覆盖源。
这套流程里,我个人觉得最值钱的是两个动作:netplan try和重启验证。前者保命,后者保稳。很多人省掉这两步,结果要么当场失联,要么过几天莫名其妙失效,回头排查的成本远高于当初多花的两分钟。
最后分享一个小技巧:把每次的配置文件和对应的网络环境(网段、网关、DNS)记在一个文本文件里,放在/root/network-notes.txt或者你自己的文档里。换机器、重装系统、帮别人配网络的时候,直接翻记录改两个数字就能用,比每次重新推导快得多。网络配置这东西,写对了不难,难的是在出问题的时候能快速回到一个已知正确的状态,而一份历史记录就是最好的参照系。