1. 先搞清楚“添加网关路由”到底在解决什么问题
很多人第一次在 Ubuntu 上碰到“添加网关路由”这个需求,场景往往很具体:机器有两块网卡,一块连内网、一块连外网,结果配完 IP 之后发现只能通一边;或者是在实验室、机房环境里,主机默认走了一个网关,但某个特定网段必须从另一块网卡出去,于是需要手动补一条路由。表面上看只是敲一条ip route add命令的事,但真正动手时,报错RTNETLINK answers: Network is unreachable、File exists、重启后路由消失,这些问题一个接一个。
这篇内容就是围绕 Ubuntu 下网关路由的添加、验证、持久化来展开的。我会把“默认网关”和“静态路由”这两个容易混淆的概念先掰开,再讲清楚ip route、route、netplan这几套工具各自的分工,最后给出可以直接抄的配置和排查链路。适合刚接触 Linux 网络配置的新手,也适合已经会用命令行但总在“重启失效”上翻车的朋友。核心关键词就三个:Ubuntu、网关、路由,所有内容都围绕它们转。
需要先明确一点:Ubuntu 从 17.10 之后默认用Netplan管理网络,早期教程里改/etc/network/interfaces的做法在新版本上基本失效了。这是很多人照着老文章操作却怎么都不生效的根本原因。所以下面讲的所有持久化方案,都以 Netplan 为主线,同时保留临时命令行的方式用于调试。
2. 默认网关与静态路由:两个概念别混着用
2.1 默认网关是“兜底出口”,静态路由是“专线”
用生活化的比喻:默认网关就像小区的大门,所有不知道往哪送的信件都从大门出去;静态路由则像“寄往某栋楼的信件直接走侧门”,是针对特定目的地的定向规则。一台主机可以只有一个默认网关,但可以有任意多条静态路由。
在 Ubuntu 上查看当前路由表,最直接的方式是:
ip route show典型输出长这样:
default via 192.168.1.1 dev eth0 proto static 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100 10.10.0.0/16 via 192.168.1.254 dev eth0第一行default via ...就是默认网关,最后一行10.10.0.0/16 via ...就是一条静态路由。理解这个结构,后面加路由就是往这张表里插行。
2.2 为什么“加了路由却不生效”
最常见的坑是:你加了一条ip route add 10.20.0.0/16 via 192.168.2.1,结果报Network is unreachable。原因不是命令写错,而是网关本身必须和某块网卡在同一网段且该网卡已 up。换句话说,你要指定的下一跳地址,主机得先能“够得着”它。如果192.168.2.1所在的网段根本没有配置在任何一个接口上,内核就拒绝添加这条路由。
排查顺序应该是:先ip addr确认接口和 IP,再ip link确认接口是 UP 状态,最后才加路由。这个顺序我踩过不止一次坑——有次网卡是 down 的,我盯着路由命令看了半天,其实是链路层没起来。
2.3 临时路由和永久路由的边界
命令行ip route add加的路由是临时的,重启或者网络服务重启就没了。它适合调试阶段快速验证“这条路由加上去能不能通”。验证通过之后,必须落到 Netplan 配置文件里才算真正完成。很多人图省事只用命令行,结果服务器一重启业务就断,回头排查半天才发现路由丢了。所以我的习惯是:命令行验证 → 确认可达 → 立刻写进 Netplan →netplan apply→ 再验证一遍。
3. 用 ip route 命令做临时验证的完整手法
3.1 添加、删除、查看三件套
临时操作全部围绕ip route子命令。添加一条到指定网段的路由:
sudo ip route add 10.20.0.0/16 via 192.168.2.1 dev eth0删除同一条路由:
sudo ip route del 10.20.0.0/16 via 192.168.2.1 dev eth0如果只是想换默认网关(比如临时切到备用线路),先删旧的再加新的:
sudo ip route del default sudo ip route add default via 192.168.1.254 dev eth0这里有个细节:del default会把当前默认路由删掉,如果新网关加不上,机器就彻底没出口了。所以更稳妥的做法是用ip route replace:
sudo ip route replace default via 192.168.1.254 dev eth0replace的语义是“有则替换、无则新增”,一步到位,不会出现中间的空窗期。这个技巧在远程操作服务器时尤其重要——你永远不想因为删了默认路由又没加上,把自己 SSH 连接搞断。
3.2 指定出口网卡和源地址
多网卡环境下,光指定via有时不够,还需要用dev明确出口网卡,用src指定源 IP:
sudo ip route add 172.16.5.0/24 via 192.168.2.1 dev eth0 src 192.168.2.100为什么要指定src?因为当一台机器有多个 IP 时,内核选源地址的逻辑不一定符合你的预期,尤其是策略路由场景。显式指定源地址能避免“包发出去了但回包回不来”的单通问题。这个参数在普通单网卡环境可以省略,但多网卡环境建议养成习惯。
3.3 验证路由是否真的生效
加完路由别急着收工,用ip route get做定向查询,比看整张表更直观:
ip route get 10.20.1.5输出会明确告诉你“去这个地址会走哪条路由、从哪个网卡出、源地址是什么”。如果输出里via和dev都符合预期,说明路由匹配正确。再配合ping或traceroute做连通性验证,基本就能确认这条路由是通的。
提示:
ip route get只做路由查找,不发包,所以即使目标不可达它也能告诉你内核会怎么选路,是排查路由优先级问题的利器。
4. Netplan 持久化:让路由熬过重启
4.1 Netplan 配置文件的结构
Ubuntu 的 Netplan 配置放在/etc/netplan/目录下,通常是01-netcfg.yaml或50-cloud-init.yaml这类命名。文件是 YAML 格式,缩进极其敏感——必须用空格,不能用 Tab,这是新手最容易翻车的地方,一个 Tab 就能让netplan apply报语法错误。
一个带静态路由的典型配置长这样:
network: version: 2 ethernets: eth0: addresses: - 192.168.1.100/24 routes: - to: default via: 192.168.1.1 - to: 10.20.0.0/16 via: 192.168.2.1 nameservers: addresses: [8.8.8.8, 1.1.1.1]注意routes下面用to: default表示默认网关,这是 Netplan 较新版本的写法;老版本用gateway4,但该字段已废弃,新系统上继续用会收到警告甚至不生效。静态路由则用to: 网段加via: 下一跳的组合。
4.2 多网卡场景下的路由写法
如果机器有两块网卡,一块eth0走内网、一块eth1走外网,配置要分开写,并且默认网关只能有一个:
network: version: 2 ethernets: eth0: addresses: - 192.168.1.100/24 routes: - to: 10.20.0.0/16 via: 192.168.1.254 eth1: addresses: - 203.0.113.10/24 routes: - to: default via: 203.0.113.1这里eth0只承担内网定向路由,eth1承担默认出口。这样内网流量走eth0,其余全部走eth1,职责清晰。如果反过来把默认网关配在eth0上,外网流量就会从内网网卡出去,大概率不通。
4.3 应用配置与回滚
改完 YAML 之后执行:
sudo netplan apply如果配置有语法错误,命令会直接报错并指出行号,这时候不要慌,也不要反复 apply,先按报错修 YAML。更稳妥的做法是先用netplan try:
sudo netplan try它会应用配置并给你 120 秒确认窗口,期间如果网络断了没按回车确认,会自动回滚到之前的配置。这个机制在远程改网络配置时简直是救命稻草——我见过太多人netplan apply之后 SSH 直接掉线,再也连不上,只能去机房接显示器。
注意:
netplan try的回滚依赖终端交互,如果你在脚本里跑或者没有交互终端,它可能不会按预期工作,这种场景还是老老实实先备份配置文件。
5. 那些年踩过的路由坑与排查链路
5.1 报错 “Network is unreachable” 的完整排查
这个报错我遇到过至少三种成因,排查要按链路层到网络层逐层来:
| 排查步骤 | 命令 | 判断依据 |
|---|---|---|
| 接口是否 UP | ip link show eth0 | 状态含UP才算起来 |
| 接口是否有 IP | ip addr show eth0 | 有inet行且网段正确 |
| 网关是否同网段 | 对比 IP 与网关 | 网关必须落在接口网段内 |
| 是否有冲突路由 | ip route show | 检查是否已有同网段路由 |
有一次我帮人排查,发现他网关写的是192.168.2.1,但网卡 IP 是192.168.1.100/24,两者根本不在一个网段,内核当然拒绝。改成同网段网关后立刻正常。这个错误看着低级,但在多网卡环境里非常容易发生——复制粘贴配置时忘了改网段。
5.2 路由加了但重启就消失
这是最经典的“临时 vs 永久”问题。命令行加的路由不写进 Netplan,重启必丢。还有一种隐蔽情况:写进了 Netplan 但文件名排序不对,或者同时存在cloud-init生成的配置覆盖了你的文件。Ubuntu 云镜像上经常出现50-cloud-init.yaml和你自己建的99-custom.yaml并存,后者字典序靠后、优先级更高,但如果 cloud-init 在启动时重新生成配置,就可能把你的路由冲掉。
解决办法是检查/etc/netplan/下所有文件,确认没有重复定义同一块网卡,必要时禁用 cloud-init 的网络配置或者把自定义配置的优先级理顺。这个坑我在云主机上踩过,折腾了很久才定位到是配置被覆盖。
5.3 策略路由:当普通路由不够用时
有些场景下,同一个目的网段要根据源地址走不同出口,这时候普通路由表就不够了,需要策略路由(policy routing)。做法是建一张自定义路由表,再用ip rule把特定源地址的流量导过去:
echo "200 custom" | sudo tee -a /etc/iproute2/rt_tables sudo ip route add default via 192.168.2.1 dev eth0 table custom sudo ip rule add from 192.168.2.100 table custom这套配置同样需要持久化,Netplan 对策略路由的支持有限,通常要配合networkd的额外配置或者开机脚本。这块属于进阶内容,普通单出口场景用不上,但多线接入的服务器上很常见。我的建议是:能用普通路由解决就别上策略路由,后者排查成本高一个量级。
6. 一套可复用的配置检查清单
把上面所有内容浓缩成一套动手前的检查清单,照着走能避开八成问题:
- 先用
ip addr和ip link确认接口状态和 IP,链路层不通就别谈路由。 - 临时路由用
ip route add验证,切换默认网关优先用ip route replace避免断网空窗。 - 验证用
ip route get 目标IP,比看整张表精准。 - 持久化写进
/etc/netplan/下的 YAML,缩进用空格,默认网关用to: default。 - 应用前先
netplan try,远程操作务必留回滚余地。 - 重启后再
ip route show复查一遍,确认路由真的还在。
我个人在实际操作中的体会是,路由配置的难点从来不在命令本身,而在于“环境判断”——你得先清楚这台机器有几块网卡、各自什么网段、默认出口该给谁,命令只是最后一步的表达。把ip addr、ip link、ip route这三个查看命令用熟,大部分路由问题都能自己定位,不用到处搜教程。另外,改网络配置前备份一下/etc/netplan/目录,成本几乎为零,但关键时刻能省下跑机房的时间。