今天聊一个Ubuntu运维里最常被问到的操作:设置固定IP。我自己就碰到过不止一回——给朋友配了一台跑内网服务的Ubuntu主机,装完系统当天一切正常,SSH能连,服务也跑着。第二天早上他打电话说机器连不上了,我远程过去一看,IP从192.168.1.100变成了192.168.1.125,之前配的端口转发、防火墙规则、域名解析全乱套了。原因不复杂——装系统时选的是DHCP自动获取,路由器给的租约到期以后,地址就被换掉了。服务器、开发板、虚拟机上这种情况最多,解决办法只有一个:给Ubuntu设置固定IP,也就是常说的静态IP。
1. 为什么需要固定IP:先从“重启就失联”这种糟心事说起
DHCP本身是个好东西,它把“谁用哪个地址”这件事自动化了。你打开手机连家里的Wi-Fi,地址是自动拿的;临时拉一台笔记本到公司网口,插上就能上网,靠的也是DHCP。但DHCP默认是按“租约”分配地址的,租约到期后客户端要重新申请,路由器完全可能给你换一个IP。对日常上网来说无所谓,但对需要被别人访问的设备来说就是灾难。
所以我一般会建议下面这些场景直接把固定IP配好:
- 跑SSH服务的服务器,不管物理机还是虚拟机,IP一变你的SSH配置、脚本、别名全失效
- 局域网里的自建服务,比如NAS、GitLab、Jellyfin、打印机共享,别人访问的是地址不是主机名
- 开发板调试,树莓派、香橙派、RK系列的板子,用网线直连或接路由器,固定IP能省掉每次查地址的麻烦
- 虚拟机的桥接/NAT模式,虚拟机重启后IP漂移会让你所有端口映射白做
- 需要做端口转发、内网穿透、DDNS的设备,公网映射目标必须是固定不变的
反过来,如果只是普通上网、访问别人的服务,那DHCP不仅够用,还更省心。固定IP不是“越显专业越好”,适合场景才是关键。
1.1 “固定IP”到底固定的是什么
很多人第一次接触时以为固定IP就是把“网络设置”里的IP地址手动填一下那么简单。其实这里有两个层面:一层是设备端配置,也就是操作系统不再向DHCP要地址,而是自己根据你填的地址、掩码、网关、DNS来激活网卡;另一层是网络端配合,你的IP必须落在当前网段的合法范围内,不能和别的设备冲突,网关地址要真实存在。
简单打比方:DHCP是每次进酒店都让前台给你分配一个房间号,固定IP是你长期租了一个固定房号,前台不用管你,你也别去跟别人抢同一间房。设备端配置是对的,但地址本身选得不合适,照样上不了网。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Ubuntu网络管理文件的三个世代:先找准要改哪个文件
很多人在网上搜到教程,照着改 /etc/network/interfaces,改完发现 netplan 命令根本不存在,或者 /etc/netplan 目录是空的。又有人在18.04上照着老教程改interfaces,重启后IP还是老样子。原因是Ubuntu的网络配置机制这几年变过好几次,不同版本、不同发行形态(Desktop还是Server)要改的文件完全不一样。
2.1 再看到interfaces文件别惊讶:ifupdown时代的老写法
Ubuntu 16.04及更早的版本,以及17.04之前,系统默认的网络管理方式是ifupdown,配置文件是 /etc/network/interfaces。那个年代配静态IP的经典写法是:
bash复制auto eth0
iface eth0 inet static
address 192.168.1.100
netmask 255.255.255.0
gateway 192.168.1.1
dns-nameservers 223.5.5.5
现在如果你在用18.04以后的新版本,照这个配大概率无效,因为默认网络管理工具已经换成netplan了。但少数精简版、容器里或者某些嵌入式Linux依然保留这种写法,所以看到它别陌生,只是别在新系统上去改它。
2.2 从17.10开始引入的netplan:声明式的YAML配置
Ubuntu从17.10开始引入netplan,它是一个“声明式”的网络配置工具。所谓声明式,就是你只描述“最终希望网络长什么样”——比如哪块网卡用什么地址、走哪个网关、DNS填多少——至于底层是调systemd-networkd还是NetworkManager去实现,由netplan帮你协调。配置文件以YAML格式存放在 /etc/netplan/ 目录下,文件名常见的有:
/etc/netplan/01-netcfg.yaml(手工部署常见)/etc/netplan/00-installer-config.yaml(Ubuntu Server安装器生成的默认文件)/etc/netplan/50-cloud-init.yaml(安装了cloud-init的镜像会用它)
查询当前系统里实际有哪些netplan配置文件,用 ls /etc/netplan/ 看目录就行,一般只需要改其中一个有 ethernets 定义的。
2.3 Desktop版还要注意NetworkManager在“抢戏”
桌面版Ubuntu的情况稍微特殊。系统虽然也装了netplan,但实际管网的往往是NetworkManager。你在桌面右上角的网络设置里改IP,写进的是NetworkManager的配置,而不是 /etc/netplan/ 下的YAML。反过来,你在netplan文件里写固定IP,但renderer(渲染器)如果写的是 NetworkManager,那么是NetworkManager去执行netplan的声明;如果写networkd,则交给systemd-networkd执行。后面会专门说renderer这个字段,这里你先记住:改文件前先分清楚系统里到底是谁在管理网络。
对于版本对不上号的同学,我有一个笨办法:不管你在哪个版本,先执行 ip a 和 nmcli device status 看当前网卡和网络服务状态,再 ls /etc/netplan/ 看有没有YAML文件。这三个命令合起来,基本能判断该改哪个文件。
3. 分场景配置实操:Server、桌面版、虚拟机、开发板各来一遍
有图形界面和没有图形界面的配置路线完全不同。我先按最常见的几个场景逐个演示,你可以直接找到对应的那一节照抄。
3.1 场景一:Ubuntu Server(20.04/22.04/24.04)用netplan配置
这是服务器场景最标准的做法。整个过程四步:确认网卡名、改YAML、试配置、应用配置。
首先查看网卡名称:
bash复制ip a
输出里会有一个形如 ens33、ens18、eth0、enp3s0 的名字,这就是你要配置的物理网卡。不同VMware版本默认叫ens33,VirtualBox可能叫enp0s3,物理机可能是enp5s0之类,别照抄教程里的eth0,以自己机器上显示的实际名字为准。
接着备份原文件。注意先 ls /etc/netplan/ 确认实际文件名,不要照抄我的 00-installer-config.yaml:
bash复制sudo cp /etc/netplan/00-installer-config.yaml /etc/netplan/00-installer-config.yaml.bak
然后编辑,以Ubuntu Server 22.04为例,把文件内容改成:
yaml复制network:
version: 2
ethernets:
ens33:
dhcp4: false
addresses:
- 192.168.1.100/24
routes:
- to: default
via: 192.168.1.1
nameservers:
addresses:
- 223.5.5.5
- 119.29.29.29
这里的关键点是:addresses 里写的 192.168.1.100/24,斜杠后面的24就是子网掩码255.255.255.0的CIDR写法;routes 里 to: default 是默认路由,via 是网关地址;nameservers 里填的是DNS。这三件事对应的是手动配IP时必须给全的四个要素:地址、掩码、网关、DNS。
改完先别急着 apply,先运行:
bash复制sudo netplan try
提示:netplan try 的120秒等待时间足够你把关键配置重新改回来。SSH操作时如果不小心把路由改错,2分钟后系统自动回滚,这也是它比 apply 安全得多的原因。
netplan try 会先验证YAML语法并应用配置,然后等120秒。如果这120秒内你没有按回车确认,它会自动回滚到之前的配置。这个设计对SSH远程连接特别友好——万一你把自己锁在外面,至少过两分钟系统会自己恢复。确认无误后按回车保留生效。
如果确认没问题,直接跑 sudo netplan apply 让它永久生效。apply和try的区别在于,apply不会等回滚确认,立刻应用并且一直保持,所以远程操作时优先用try,本地操作无所谓。
验证配置是否生效:
bash复制ip a
ip route show
看到ens33上绑定了 192.168.1.100/24,且 default via 192.168.1.1,就说明配置成了。
3.2 场景二:Ubuntu Desktop的图形界面配置
桌面版不用碰YAML,直接在设置里操作。打开 设置 -> 网络 -> 你连接的那个有线网络的齿轮图标 -> IPv4,把方式从“自动(DHCP)”改成“手动”,然后填:
- 地址:192.168.1.100
- 掩码:255.255.255.0(图形界面有时显示为“子网掩码”)
- 网关:192.168.1.1
- DNS:223.5.5.5
填完点“应用”再关闭窗口,通常就生效了。这种配置会写进NetworkManager的配置目录,路径大概是 /etc/NetworkManager/system-connections/ 下对应的连接文件,由NetworkManager管理,重启也会保留。
有一个细节值得提醒:如果你之前在图形界面里配过IP,又去 /etc/netplan/ 里改YAML,两者会互相干扰。桌面环境的网络图标上如果显示“未托管”(unmanaged)之类的状态,多半是netplan和NetworkManager在抢网卡,后面排查篇会细说。
3.3 场景三:VMware/VirtualBox虚拟机里的固定IP
虚拟机里配固定IP,首先要搞清楚虚拟网卡的工作模式。VMware里常见的有NAT、桥接和仅主机三种。NAT模式下,虚拟机的网络走虚拟网卡VMnet8,网段默认一般是192.168.x.0/24,网关是192.168.x.2或192.168.x.1,具体可以在 VMware 的 编辑 -> 虚拟网络编辑器 里看到;桥接模式下虚拟机相当于接在物理局域网里,IP网段、网关都和物理机一致。VirtualBox的NAT网段通常是10.0.2.0/24,网关是10.0.2.2;桥接模式则同样要跟物理局域网保持一致。
在虚拟机里配置的方法和3.1节完全一样。最容易出错的是这三个点:
- NAT模式下,你填的固定IP必须是VMnet8同网段且没被占用的一个,不能随便填
- 桥接模式下,子网掩码、网关、DNS必须跟物理网络环境一样,比如物理机是192.168.50.0/24,网关192.168.50.1,虚拟机就别填成192.168.1.x
- 克隆虚拟机之后,网卡的MAC地址变了,所有依赖旧MAC的配置(DHCP保留、netplan里match的macaddress)都会失效,建议克隆后重新检查一遍网卡名和配置文件
3.4 场景四:开发板上的特殊提醒
树莓派这类板卡很多用NetworkManager或systemd-networkd,未必走netplan。有的板子连电脑后会出现一个USB网卡,名字叫 usb0 或 enx 加上一串MAC,这是USB有线网卡,配置思路一样,但网卡名不是eth0。我的建议是:先运行 ip a 看名字,再判断系统用的是netplan还是NetworkManager,别从网上随便抄一段就往上贴。
4. netplan字段详解:缩进、renderer、routes和容易被忽略的坑
如果只看上面的示例,你可能觉得netplan很简单。但实际项目中,十个报错有六七个出在配置文件的细枝末节上。这一节我把每个关键字段的意思和容易踩的坑讲透。
4.1 最重要的知识点:renderer是谁在执行
netplan文件里可以声明:
yaml复制network:
version: 2
renderer: networkd
renderer指定的是“由哪个后台服务真正应用这份配置”。可选值是 networkd(systemd-networkd)和 NetworkManager。Ubuntu Server默认是networkd,桌面版默认会是NetworkManager。如果你在Server上把renderer改成NetworkManager,但系统里没有启动NetworkManager服务,配置会应用失败;反过来,在桌面版上希望netplan管网,renderer却写成networkd,可能会让桌面右上角的网络设置失灵。
我的经验是:除非明确知道自己在干嘛,否则不要动renderer。它默认是哪个就用哪个。
4.2 addresses为什么必须写/24
不少从别的系统转过来的同学习惯写成 address: 192.168.1.100 和 netmask: 255.255.255.0 两个字段,这在netplan里是能识别的,但官方更推荐在addresses里用CIDR格式一次性表达地址和掩码。addresses是一个列表,可以一次写多个:
yaml复制addresses:
- 192.168.1.100/24
- 10.0.0.10/24
表示同一张网卡上绑了两个网段的地址。这种用法在做多网段访问时很有用,但普通单网卡场景别贪多,地址越多问题越难查。
4.3 老教程里的gateway4已经废弃了
如果你翻到两三年前的教程,会看到这种写法:
yaml复制ethernets:
ens33:
gateway4: 192.168.1.1
gateway4 在较新版本的netplan里会打印弃用警告,继续用可能导致配置应用失败。官方推荐的替代写法就是本教程前面用的routes方式:
yaml复制routes:
- to: default
via: 192.168.1.1
routes字段是一个列表,除了默认路由,你还可以添加去特定网段的静态路由。比如要让访问192.168.10.0/24的流量走10.0.0.1这个网关,就再加一条:
yaml复制routes:
- to: default
via: 192.168.1.1
- to: 192.168.10.0/24
via: 10.0.0.1
这套表达方式比gateway4更通用,也更容易理解。
4.4 nameservers:DNS不生效是很多人不会查的盲区
nameservers 下面可以写 addresses(DNS服务器列表)和 search(域名搜索后缀):
yaml复制nameservers:
addresses:
- 223.5.5.5
- 119.29.29.29
search:
- home.local
search是给“只写主机名就能自动补全域名”的场景用的,普通用户可以不写。DNS配置有一个隐藏问题:如果你的renderer是systemd-networkd,那么生效后 /etc/resolv.conf 会被systemd-resolved接管,里面写的是127.0.0.53这样的本地地址,而不是你填的223.5.5.5。这会让很多人误以为DNS没生效。要确认实际DNS解析用的是谁,用:
bash复制resolvectl status
在输出的“当前DNS服务器”一栏能看到真正生效的DNS地址。能ping通IP但ping不通域名时,90%的根因都出在这一层。
4.5 YAML缩进:配置没生效的头号嫌疑犯
netplan使用YAML格式,YAML对缩进极其敏感,而且只认空格,不认Tab键。一个典型的错误写法是把 nameservers 和 addresses 对齐错了,导致netplan try时报“无效的YAML”或者干脆不把DNS归到ens33下。我自己排过不少这类问题,判断办法是用可视化缩进的编辑器(VS Code、vim开启缩进线),sublime也行。
还有一个我碰到的案例:文件里出现了Tab,语法检测可能不报错,但应用后行为诡异。解决办法很简单,任何时候改完都先跑 sudo netplan try,它有强制的语法校验。
4.6 optional: true是干什么的
如果系统里有多块网卡,其中一块启动很慢,或者根本不存在固定网络(比如偶尔拿笔记本到没有网线的地方),配置文件中最好给这块网卡加上 optional: true:
yaml复制ethernets:
enp3s0:
dhcp4: true
optional: true
optional的意思是:即使这块网卡没起来,也不要阻塞整个networkd的启动流程。不加它,在boot阶段系统可能因为等待网卡超时,拖慢开机好几秒,极端情况会导致登入后网络全挂。对笔记本、移动设备、可插拔网卡来说,这是个小而关键的字段。
5. 固定IP后网络不通?按这套链路从症状到根因排查
配置写得再标准,也保不齐遇到环境里的各种奇葩问题。我把最常见的四类症状和对应的排查思路整理成了一条链路,遇到问题按顺序往下走就行。
5.1 症状A:apply后IP没变化,或者配置根本没生效
先确认你有没有改对文件、有没有执行成功:
bash复制sudo netplan apply
ip a
如果 ip a 里网卡显示的还是DHCP拿到的地址,说明要么你改的文件不是当前生效的那个(比如系统里同时存在多个netplan文件),要么是NetworkManager在和你抢管理权。这时用 nmcli device status 看网卡是由谁管理的——如果显示state=connected、device=ens33是由NetworkManager管理,那就别在netplan里跟它较劲,直接用 nmcli 命令设置静态IP会更痛快。
另一个常见原因是cloud-init。云镜像或某些虚拟机模板启用了cloud-init,它在启动时会重新生成网络配置,把你手写的改动覆盖掉。此时应该优先去查 /etc/netplan/ 下有没有50-cloud-init.yaml,以及 /var/lib/cloud/ 下的状态。处理方式后面第六节细说。
5.2 症状B:IP确实是固定了,但ping不通网关
用 ip route show 看默认路由在不在。如果default路由没有,或者via的IP写错了,包根本出不了本机。其次检查网关是否真实存在、是否可达。有的路由器会开启AP隔离、有时候交换机端口配了隔离策略,也会导致IP通了但网关不回包。把电脑接到同一台路由器下,手动ping网关验证一下,能很快缩小范围。
5.3 症状C:能ping通网关,但解析不了域名
先ping一个公共IP,比如223.5.5.5:
bash复制ping 223.5.5.5
通就说明网络链路正常,问题在DNS。按4.4节的办法用 resolvectl status 查看实际生效的DNS。如果 /etc/resolv.conf 里不是指向systemd-resolved,而是被其他程序改写了,可以手动把它重新链接:
bash复制sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
注意:这个命令在不同Ubuntu版本上略有差异,建议先 cat /etc/resolv.conf 看一眼原来指向哪里再操作。
5.4 症状D:重启后配置又变回DHCP了
这多半是系统里存在多个网络配置文件同时生效。查看 /etc/netplan/ 和 /etc/NetworkManager/system-connections/ 下的文件,看是否有重复配置。另外还要检查cloud-init,万一它的配置文件比netplan优先级高,每次开机都会覆盖你的改动。优先级顺序通常是:cloud-init生成的50-cloud-init.yaml > 用户手写的xx-xxx.yaml,具体要看文件名的字典序和渲染器行为。
5.5 排查过程中我用过的高频命令汇总
| 目的 | 命令 |
|---|---|
| 查看网卡和IP | ip a |
| 查看路由 | ip route show |
| 查看DNS运行状态 | resolvectl status |
| 查看当前resolv.conf指向 | ls -l /etc/resolv.conf |
| 查看systemd-networkd日志 | journalctl -u systemd-networkd |
| 查看NetworkManager日志 | journalctl -u NetworkManager |
| 应用netplan配置 | sudo netplan apply |
| 测试性应用+自动回滚 | sudo netplan try |
拿到一套报错信息后,我通常先看journalctl里systemd-networkd的报错,它往往直接告诉你网卡是不是“Failed to configure”或者“Could not set route”,比反复猜配置有效得多。
6. 容易忽略的收尾细节:IP冲突、多网卡、云服务器与cloud-init
配置能ping通了,看起来大功告成,但有几个“之后才爆发”的细节,配置完当天可能一切正常,过几天才暴露。这里集中说一下,都是实操里真实遇到过的。
6.1 配置前必须做的两件事
第一,备份当前配置和当前IP。改配置之前先 ip a 看一下现在用的IP、掩码、网关,并记录到一个临时文件里。万一配置完崩了,至少知道原来的网络长什么样,能快速改回去。
第二,检查目标IP有没有被占用。最简单的办法是在配置前用另一台设备ping一下这个IP,或者用 arp-scan 扫一遍局域网:
bash复制sudo arp-scan -l
如果发现192.168.1.100已经有设备应答,千万不要硬配,宁可换一个IP。IP冲突引发的故障非常隐蔽——两台机器同时用同一个IP,表现是时通时断,运气好完全正常,运气差整个网段都怪怪的。
6.2 多网卡时,默认路由可能不是你想象的那条
服务器如果有多块网卡,常见于物理机或做了网卡绑定的虚拟机,netplan里每块网卡都可以写routes。问题是如果你给两张网卡都写了 to: default,系统启动时会选择Metric(路由度量值)小的那条作为默认路由,不一定是你在配置文件里最后写的那条。多网卡场景建议只让一张网卡承担默认路由,其他网卡只配置局域网段的静态路由,否则后期网络时通时断,排查起来非常痛苦。
6.3 云服务器别在配置文件里硬改IP
阿里云、腾讯云、AWS这类云服务器上,以管理员身份手写netplan固定IP往往是一个坑。云平台的网络是SDN(软件定义网络)在撑着的,控制台里显示的“私有IP”“主网卡IP”才是真正的配置来源,操作系统内的地址通常是平台下发或cloud-init生成的。你如果在云服务器里强行改netplan,很可能会把网络改挂,重启用控制台恢复反而更麻烦。正确做法是:在云平台控制台的VPC/网卡页面里把IP设为“保留”,或者在操作系统里只改DNS、路由,不动IP地址本身。
6.4 cloud-init:服务器上最容易被忽略的“幕后黑手”
对Ubuntu Server尤其明显:安装系统的时候如果勾选了cloud-init相关选项,或者拿到的是云厂商定制镜像,系统里几乎一定会有一个 /etc/netplan/50-cloud-init.yaml,并且cloud-init服务会在启动时重新生成它。你辛辛苦苦写好的固定IP,可能每次开机都被重置。两条解决路线我建议优先用第一条:
- 如果确实不需要cloud-init,禁用它的网络模块:编辑
/etc/cloud/cloud.cfg.d/99-disable-network-config.cfg,写入network: {config: disabled},然后sudo cloud-init clean之后重启。要谨慎,确保自己不需要云初始化功能。 - 如果保留cloud-init,就把固定IP写进它读的源配置里,而不是手改
/etc/netplan。这个相对复杂,具体看云厂商文档。
我在本地虚拟机里试过好几次,装上Ubuntu Server 24.04后如果镜像来自官方Cloud Image,不改cloud-init配置,你写的netplan文件很容易被覆盖。本地手工安装的ISO则通常没有这个烦恼,先 ls /etc/netplan/ 看有没有cloud-init字样,再决定怎么下手。
6.5 网卡偶尔激活失败?先检查链路协商
固定IP配好、网段也对,但网卡偶尔激活失败,这种情况我遇到过一个典型的:网线插着,系统日志里报链路down/up反复抖动。这时用 ethtool ens33 看网卡速度和双工模式,通常会自动协商,不必手动改。真遇到自动协商问题,可以尝试 ethtool -s ens33 speed 1000 duplex full,但先确认网线和设备都支持,否则强行指定反而先有各种问题。链路问题排查优先级在配置问题之后,别一上来就怀疑配置文件。
6.6 用nmcli在桌面版上逆向配置
补一个桌面版专属但很多人不知道的操作:即使Ubuntu Desktop默认用了NetworkManager,你也能用命令直接配置静态IP,不需要图形界面。先看连接名:
bash复制nmcli connection show
拿到连接名(比如“Wired connection 1”)后,这样配置:
bash复制nmcli connection modify "Wired connection 1" ipv4.method manual ipv4.addresses 192.168.1.100/24 ipv4.gateway 192.168.1.1 ipv4.dns "223.5.5.5 119.29.29.29"
nmcli connection up "Wired connection 1"
这对只能SSH的机器特别实用,你不需要图形界面,也能把网卡的固定IP配好。识别连接名时注意带引号和大小写。
再回到开头的故事:我的那位朋友最终就是用netplan文件配好固定IP解决的。从那次之后,我给自己立的规矩是:凡是跑服务的Ubuntu机器,装完系统第一件事就是把IP钉死,第二步设置反向解析和主机名,第三步确认重启后SSH能自动连回来。整个过程熟练以后十分钟搞定,却能避免无数个“重启失联”的早晨。
最后再分享一个关于使用习惯的小建议:如果你的局域网路由器支持DHCP静态租约(DHCP Reservation),其实比在每台设备上手工配静态IP更省心。在路由器后台把设备MAC地址和固定IP绑定,设备端全用DHCP,地址也不会变。这样设备端配置量最少,也不容易出现手快点错、把配置改挂的问题。但有些场景你控制不了路由器,比如公司机房、大学实验室,那设备端netplan还是得学会配。两条路都掌握,才算真正把“设置固定IP”这件事吃透。
