How to add a persistent static route¶
Use this guide when a network can't be reached through the default gateway and needs its own route through another router.
The example sends traffic for 203.0.113.0/24 through the gateway 192.0.2.1, which is on the same network segment as the interface <INTERFACE>.
Before you begin¶
<INTERFACE>stands for the name of the interface that reaches the gateway, such asenp0s4. List the interfaces and their addresses withip -br addr show.- The interface already has a persistent address on the gateway's network, such as
192.0.2.10/24, configured with the distribution's default network tooling. The kernel only accepts a gateway that it can reach directly through a connected network. - You need
sudoaccess.
Warning
A wrong route can cut off your own connection, for example if the destination you enter includes the address you're connecting from.
Make changes from a console, or check that the destination doesn't cover the address of your SSH client before you apply them.
To roll back a route you added with ip, delete it with ip route del (step 3); a route from the persistent configuration disappears when you remove it from the file or profile and apply the change.
Steps¶
-
Add the route to the running kernel, to test it before you make it permanent:
-
Check that the kernel would now send traffic for the network through the gateway:
$ ip route show 203.0.113.0/24 203.0.113.0/24 via 192.0.2.1 dev enp0s4 $ ip route get 203.0.113.25 203.0.113.25 via 192.0.2.1 dev enp0s4 src 192.0.2.10 uid 1000 cacheIf hosts in
203.0.113.0/24answer as you expect (for example withping), the route is correct. -
Remove the test route, so that it doesn't conflict with the persistent one:
A route added with
ip routeis lost at the next reboot in any case. -
Add the route to the persistent configuration of the interface:
Which tool configures the interface depends on how the system was installed:
- ifupdown on Debian systems installed with the Debian installer without a desktop: the interface has an
iface <INTERFACE>stanza in/etc/network/interfacesor in a file in/etc/network/interfaces.d/. - netplan on Debian cloud images and on Ubuntu cloud and server installations: the interface is defined in a file in
/etc/netplan/, and netplan hands the configuration to systemd-networkd. - NetworkManager on desktop installations: use the RHEL/Alma/Rocky instructions.
If ifupdown configures the interface, show its stanza:
$ grep -A2 "^iface <INTERFACE>" /etc/network/interfaces iface enp0s4 inet static address 192.0.2.10/24Add an
upline with theip route addcommand to the stanza, with a text editor or with this command:sudo sed -i "/^iface <INTERFACE> inet static/a\ up ip route add 203.0.113.0/24 via 192.0.2.1" /etc/network/interfacesifupdown runs the
upcommand each time it brings the interface up, after configuring the address. The stanza now looks like this:auto enp0s4 iface enp0s4 inet static up ip route add 203.0.113.0/24 via 192.0.2.1 address 192.0.2.10/24Warning
Restarting an interface interrupts its connections. Don't restart the interface your SSH session uses unless you have a console.
Restart the interface to apply the change:
<!-- verify-setup
Switch the lab to the netplan starting point for the next branch.¶
ifdown "$LAB_NIC2" sed -i "/^auto $LAB_NIC2\$/,\$d" /etc/network/interfaces rm -f /etc/systemd/network/05-lab-unmanaged.network printf 'network:\n version: 2\n ethernets:\n %s:\n addresses:\n - 192.0.2.10/24\n' "$LAB_NIC2" > /etc/netplan/60-static.yaml chmod 600 /etc/netplan/60-static.yaml netplan apply for i in $(seq 30); do ip -4 addr show dev "$LAB_NIC2" | grep -q 'inet 192.0.2.10/24' && break; sleep 1; done ip -4 addr show dev "$LAB_NIC2" | grep -q 'inet 192.0.2.10/24' test -z "$(ip route show 203.0.113.0/24)" →
If netplan configures the interface, find the netplan file that defines it:
Add the route to that file with
netplan set. Pass the file name without.yamlas--origin-hint, so that the setting is written to the same file:sudo netplan set --origin-hint 60-static \ "ethernets.<INTERFACE>.routes=[{to: 203.0.113.0/24, via: 192.0.2.1}]"The file now contains a
routeslist under the interface; you can also add the same lines with a text editor:$ sudo cat /etc/netplan/60-static.yaml network: version: 2 ethernets: enp0s4: addresses: - "192.0.2.10/24" routes: - to: "203.0.113.0/24" via: "192.0.2.1"Apply the configuration:
Edit only the files in
/etc/netplan/. The10-netplan-*.networkfiles thatnetworkctl statusshows in/run/systemd/network/are generated from them and overwritten bynetplan applyand at boot.NetworkManager manages the network. Find the name of the connection profile that's active on
<INTERFACE>:Add the route to that profile, replacing
<CONNECTION>with the profile name, and reactivate the profile to apply it:sudo nmcli connection modify "<CONNECTION>" +ipv4.routes "203.0.113.0/24 192.0.2.1" sudo nmcli connection up "<CONNECTION>"Check what the profile now contains:
The Arch Linux cloud image configures the network with systemd-networkd. Find the
.networkfile that applies to<INTERFACE>:$ networkctl status <INTERFACE> | grep 'Network File' Network File: /etc/systemd/network/20-static.networkAppend a
[Route]section to that file, replacing<NETWORK_FILE>with its path, and reload systemd-networkd:sudo tee -a <NETWORK_FILE> > /dev/null << EOF [Route] Destination=203.0.113.0/24 Gateway=192.0.2.1 EOF sudo networkctl reloadIf you manage the network with NetworkManager instead, use the RHEL/Alma/Rocky instructions.
OpenRC with netifrc reads the network configuration from
/etc/conf.d/net, where the interface's address is set in aconfig_<INTERFACE>line. Add aroutes_<INTERFACE>line for the route:sudo tee -a /etc/conf.d/net > /dev/null << EOF routes_<INTERFACE>="203.0.113.0/24 via 192.0.2.1" EOFIn these variable names, any character of the interface name other than a letter, digit or underscore is replaced by an underscore. The file now contains both lines:
Restart the interface's service to apply the change; its output includes an
Adding routesline for the new route:On the systemd profile, systemd-networkd configures the network: follow the Arch instructions (systemd profile, not verified).
- ifupdown on Debian systems installed with the Debian installer without a desktop: the interface has an
-
Check that the route is back, this time from the persistent configuration:
The details after the device name vary with the tool: NetworkManager shows
proto static metric 101, and netifrc shows only a metric, such asmetric 3.
Verify¶
Restart the system at a convenient time, to make sure the route is restored at boot:
After the restart, the route is present without any manual step:
Troubleshooting¶
Error: Nexthop has invalid gateway.- The gateway isn't on any network the system is directly connected to.
Check that
<INTERFACE>is up and has an address on the gateway's network withip -br addr show dev <INTERFACE>. RTNETLINK answers: File exists- A route to the same destination already exists, for example from an earlier test.
Show it with
ip route show 203.0.113.0/24and delete it withip route delbefore you add it again. - The route is missing after a reboot
- The interface's persistent configuration wasn't applied, often because the route was added to a different file or profile than the one that's active on the interface.
Check which configuration applies to the interface:
sudo grep -l <INTERFACE> /etc/netplan/*.yaml(netplan; the10-netplan-*files in/run/systemd/network/are generated and must not be edited), theiface <INTERFACE>stanza in/etc/network/interfacesor/etc/network/interfaces.d/(ifupdown),networkctl status <INTERFACE>(systemd-networkd),nmcli device show <INTERFACE>(NetworkManager), or/etc/conf.d/net(netifrc).
Related¶
- Tutorial: Configure a static IP address
- Reference: ip, ss and nmcli
- Explanation: How Linux routes packets