How to Fix Netplan Multiple Default Routes on Ubuntu: Policy Routing, Metrics and Two-NIC Servers
Configuring two network interfaces on Ubuntu is easy—until both interfaces need their own gateway.
A typical server may have one interface connected to a public or management network and another connected to a private, storage, backup, or application network. Everything can look correct at first: both interfaces are up, both IP addresses respond to ping, and Netplan accepts the YAML configuration.
Then the strange behavior begins.
SSH works through one address but not the other. Connections arrive through one interface and replies leave through another. Internet access works only intermittently. A route appears correct but Linux still chooses an unexpected interface. In other cases, Netplan warns about conflicting default routes.
These problems are usually not random. They result from the interaction between default routes, route metrics, Linux routing tables, source addresses and policy routing.
This guide explains how to configure and troubleshoot multiple default routes on Ubuntu using Netplan, including practical two-NIC configurations, route metrics, custom routing tables and source-based policy routing.
SEO Information
Meta Title: Netplan Multiple Default Routes: Ubuntu Policy Routing Guide
Meta Description: Fix Netplan multiple default routes on Ubuntu using route metrics, policy routing, custom routing tables and reliable two-NIC configurations.
Focus Keyword: Netplan multiple default routes
Secondary Keywords: Ubuntu multiple default gateways, Netplan policy routing, Ubuntu two NICs, Linux multiple default routes, Netplan route metric, source based routing Ubuntu, Netplan routing-policy
Recommended Slug: netplan-multiple-default-routes-policy-routing
Category: Networking
Search Intent: Troubleshooting / How-to / Configuration
Table of Contents
- Why Multiple Default Routes Cause Problems
- Inspect the Existing Network
- How Linux Selects a Route
- Route Metrics Explained
- Primary and Backup Gateway Configuration
- When Metrics Are Not Enough
- Source-Based Policy Routing
- Complete Netplan Two-NIC Configuration
- Apply Netplan Safely
- Verify Routing
- Troubleshoot Wrong-Interface Traffic
- DHCP and Cloud Networking Problems
- Common Mistakes
- FAQ
Why Do Multiple Default Routes Cause Problems?
Suppose an Ubuntu server has two interfaces:
enp1s0
IP: 192.168.10.10/24
Gateway: 192.168.10.1
enp2s0
IP: 10.20.30.10/24
Gateway: 10.20.30.1
Both networks provide a route beyond their local subnet.
The server could therefore end up with:
default via 192.168.10.1 dev enp1s0
default via 10.20.30.1 dev enp2s0
But a default route means:
Use this route when no more specific route matches the destination.
When two default routes coexist, Linux needs a predictable method for determining which route should handle a particular packet.
Understanding this behavior is much easier if you already understand IP addressing, gateways and routing. CorgiNetwork’s <a href=”https://corginetwork.com/computer-networking-explained/“>Computer Networking Explained</a> provides a broader networking foundation, while the <a href=”https://corginetwork.com/tcp-ip-explained-a-complete-guide-to-tcp-ip-model/“>TCP/IP Explained guide</a> explains how IP routing fits into the TCP/IP architecture.
For authoritative Netplan syntax and routing properties, keep the <a href=”https://netplan.readthedocs.io/en/stable/netplan-yaml/” target=”_blank” rel=”noopener”>official Netplan YAML reference</a> available while working through the configuration.
Inspect the Existing Ubuntu Network First
Never begin by copying a Netplan configuration from the Internet.
First determine what the server currently has.
Run:
ip -br addr
Example:
lo UNKNOWN 127.0.0.1/8
enp1s0 UP 192.168.10.10/24
enp2s0 UP 10.20.30.10/24
Then inspect the current routing table:
ip route
You might find:
default via 192.168.10.1 dev enp1s0
default via 10.20.30.1 dev enp2s0
192.168.10.0/24 dev enp1s0 proto kernel scope link src 192.168.10.10
10.20.30.0/24 dev enp2s0 proto kernel scope link src 10.20.30.10
Now inspect policy-routing rules:
ip rule
Finally, check Netplan itself:
sudo netplan get
and:
ls -la /etc/netplan/
If you want a broader reference for commands such as ip, ss, ping, dig, traceroute and tcpdump, see CorgiNetwork’s <a href=”https://corginetwork.com/linux-network-tools-guide/“>Linux Network Tools Guide</a>.
The important principle is simple:
Do not change routing until you understand who currently controls it.
Possible sources include Netplan, NetworkManager, systemd-networkd, DHCP, cloud-init, VPN software and cloud networking agents.
How Linux Selects a Route
Linux does not simply choose a gateway at random.
Routing decisions involve several factors, including:
- destination address;
- routing table;
- route prefix;
- metric;
- policy-routing rules;
- source address;
- interface state.
A highly useful diagnostic command is:
ip route get 8.8.8.8
Instead of printing the entire routing table, this asks the kernel:
Which route would you actually use to reach this destination?
For example:
8.8.8.8 via 192.168.10.1 dev enp1s0 src 192.168.10.10
This tells you the selected:
- gateway;
- interface;
- source IP.
For policy-routing configurations, you can go further:
ip route get 8.8.8.8 from 192.168.10.10
and:
ip route get 8.8.8.8 from 10.20.30.10
This becomes extremely useful later.
Understanding Route Metrics
Suppose the first interface should be the normal Internet connection while the second should have a less-preferred default route.
You can assign different metrics.
For example:
default via 192.168.10.1 metric 100
default via 10.20.30.1 metric 200
For otherwise competing routes, the lower metric generally has higher preference.
This concept is documented in Canonical’s <a href=”https://documentation.ubuntu.com/server/explanation/networking/configuring-networks/” target=”_blank” rel=”noopener”>Ubuntu Server networking documentation</a>, while Netplan exposes route metrics through its route configuration.
Primary and Secondary Gateway with Netplan
A practical configuration might be:
network:
version: 2
renderer: networkd
ethernets:
enp1s0:
addresses:
- 192.168.10.10/24
routes:
- to: default
via: 192.168.10.1
metric: 100
nameservers:
addresses:
- 1.1.1.1
- 8.8.8.8
enp2s0:
addresses:
- 10.20.30.10/24
routes:
- to: default
via: 10.20.30.1
metric: 200
After applying the configuration, Linux should have routes conceptually similar to:
default via 192.168.10.1 dev enp1s0 metric 100
default via 10.20.30.1 dev enp2s0 metric 200
For normal traffic, the first route has the preferred metric.
This configuration can work well when the design is essentially:
Primary path
+
Secondary path
But there is an important limitation.
When Route Metrics Are Not Enough
Consider an external client connecting directly to:
10.20.30.10
The request arrives through enp2s0.
However, the main routing table prefers:
default via 192.168.10.1 dev enp1s0 metric 100
The response could therefore attempt to leave through enp1s0.
Conceptually:
REQUEST
Client ----------------------> enp2s0
|
Ubuntu Server
|
Client <---------------------- enp1s0
RESPONSE
This is an asymmetric routing scenario.
Depending on the surrounding topology, stateful firewalls, NAT and upstream routing, it can produce symptoms such as:
- SSH works on one IP but not the other;
- TCP connections time out;
- applications are reachable only through one interface;
- connections establish and then stall;
- packet captures show replies on an unexpected NIC.
If you encounter TCP connectivity symptoms, CorgiNetwork’s <a href=”https://corginetwork.com/netcat-explained/“>Netcat Explained</a> guide is useful because Netcat can test individual TCP and UDP ports instead of relying only on ICMP ping.
When each interface needs to use its own gateway consistently, policy routing becomes much more important.
What Is Source-Based Policy Routing?
Traditional destination-based routing asks:
Where is this packet going?
Source-based policy routing allows the system to additionally ask:
Where did this traffic originate?
We can therefore create a policy such as:
Source 192.168.10.10
↓
Routing Table 100
↓
Gateway 192.168.10.1
and:
Source 10.20.30.10
↓
Routing Table 200
↓
Gateway 10.20.30.1
Netplan supports policy-routing rules through routing-policy, while individual routes can be assigned to custom routing tables. See the <a href=”https://netplan.readthedocs.io/en/stable/netplan-yaml/” target=”_blank” rel=”noopener”>official Netplan configuration reference</a> for the supported routes and routing-policy properties.
Complete Netplan Configuration for Two NICs and Two Gateways
Consider this topology:
enp1s0
192.168.10.10/24
Gateway 192.168.10.1
enp2s0
10.20.30.10/24
Gateway 10.20.30.1
A source-policy configuration can look like this:
network:
version: 2
renderer: networkd
ethernets:
enp1s0:
addresses:
- 192.168.10.10/24
routes:
- to: 192.168.10.0/24
scope: link
table: 100
- to: default
via: 192.168.10.1
table: 100
routing-policy:
- from: 192.168.10.10/32
table: 100
priority: 1000
enp2s0:
addresses:
- 10.20.30.10/24
routes:
- to: 10.20.30.0/24
scope: link
table: 200
- to: default
via: 10.20.30.1
table: 200
routing-policy:
- from: 10.20.30.10/32
table: 200
priority: 1100
This configuration expresses two important policies.
Traffic sourced from:
192.168.10.10
uses routing table:
100
while traffic sourced from:
10.20.30.10
uses:
200
Each table then contains its appropriate gateway.
Why Add the Connected Network to Each Table?
Notice this route:
- to: 192.168.10.0/24
scope: link
table: 100
and its equivalent for the second network.
A custom routing table should have enough information to reach the network containing its gateway and local peers.
The desired table looks conceptually like:
Table 100
192.168.10.0/24 dev enp1s0
default via 192.168.10.1
rather than containing only an isolated default route with insufficient supporting reachability.
The exact routes required depend on the topology, which is why copying a multi-homing configuration without understanding the network is risky.
Understanding routing-policy
This section:
routing-policy:
- from: 192.168.10.10/32
table: 100
priority: 1000
means traffic matching the specified source is directed to the chosen routing table according to the policy rule.
After Netplan applies the configuration, inspect the result:
ip rule
A system might conceptually show:
0: from all lookup local
1000: from 192.168.10.10 lookup 100
1100: from 10.20.30.10 lookup 200
32766: from all lookup main
32767: from all lookup default
Netplan documents policy-routing matching and priorities in its <a href=”https://netplan.readthedocs.io/en/stable/netplan-yaml/” target=”_blank” rel=”noopener”>YAML configuration reference</a>.
Route Metrics vs Policy Routing
This distinction is essential.
Route metrics answer:
Which competing route should normally have greater preference?
Example:
Gateway A → metric 100
Gateway B → metric 200
Policy routing answers:
Which routing table should this particular traffic use?
Example:
Source 192.168.10.10 → Table 100
Source 10.20.30.10 → Table 200
A useful mental model is:
Primary + backup
↓
Route metrics
Two independently routed interfaces
↓
Policy routing
This is not an absolute rule for every topology, but it is an excellent starting point.
Apply Netplan Safely
Network configuration changes can immediately disconnect a remote server.
Before modifying anything:
sudo cp -a /etc/netplan /etc/netplan.backup
Then edit the appropriate file under:
/etc/netplan/
Do not assume the filename is always:
50-cloud-init.yaml
Check first:
ls -la /etc/netplan/
Validate Before Applying
Run:
sudo netplan generate
If the YAML contains an error, correct it before applying anything.
YAML indentation is significant.
For example:
routes:
- to: default
via: 192.168.10.1
is structurally different from incorrectly indented YAML.
For the exact supported syntax, use Netplan’s <a href=”https://netplan.readthedocs.io/en/stable/netplan-yaml/” target=”_blank” rel=”noopener”>official YAML documentation</a> rather than relying on outdated examples.
Use netplan try for Remote Servers
When working over SSH, consider:
sudo netplan try
instead of immediately committing the configuration.
The <a href=”https://netplan.readthedocs.io/en/stable/netplan-try/” target=”_blank” rel=”noopener”>official netplan try documentation</a> explains that the command temporarily applies a configuration and can automatically roll it back if it is not confirmed.
This is particularly valuable when changing:
- default gateways;
- interface addresses;
- routing tables;
- policy-routing rules.
Even so, production servers should have an independent recovery mechanism such as a hypervisor console, cloud serial console, IPMI or provider recovery console.
Verify the Configuration
After applying the change, do not stop simply because Netplan reports no error.
Check the actual runtime state.
Addresses
ip -br addr
Main routes
ip route
Policy rules
ip rule
Table 100
ip route show table 100
Table 200
ip route show table 200
Every table
ip route show table all
Then ask Linux which route it will actually use.
ip route get 8.8.8.8 from 192.168.10.10
and:
ip route get 8.8.8.8 from 10.20.30.10
This is one of the most important validation steps in the entire configuration.
Test Each Interface Independently
Try:
ping -I 192.168.10.10 8.8.8.8
and:
ping -I 10.20.30.10 8.8.8.8
But remember that ping tests ICMP—not application connectivity.
For TCP testing:
nc -vz example.com 443
The <a href=”https://corginetwork.com/netcat-explained/“>CorgiNetwork Netcat guide</a> explains how Netcat can be used for direct port testing.
For HTTP/HTTPS:
curl --interface 192.168.10.10 https://example.com/
and:
curl --interface 10.20.30.10 https://example.com/
These tests help determine whether each source address has a functional path.
Use Packet Capture When Routing Still Looks Wrong
If Linux claims the correct route is being selected but connectivity still fails, observe the packets.
Capture on the first interface:
sudo tcpdump -ni enp1s0 host DESTINATION_IP
Then on the second:
sudo tcpdump -ni enp2s0 host DESTINATION_IP
Generate traffic and see which NIC actually carries it.
For deeper packet inspection, CorgiNetwork’s <a href=”https://corginetwork.com/wireshark-explained/“>Wireshark Explained</a> guide covers packet analysis concepts that complement command-line captures.
Wireshark’s own <a href=”https://www.wireshark.org/docs/wsug_html_chunked/” target=”_blank” rel=”noopener”>official User’s Guide</a> is also an excellent external reference when detailed packet analysis is required.
Don’t Forget the Firewall
Correct routing does not guarantee connectivity.
A firewall can still block the traffic.
For UFW:
sudo ufw status verbose
For nftables:
sudo nft list ruleset
CorgiNetwork’s <a href=”https://corginetwork.com/firewalls-explained/“>Firewalls Explained</a> guide explains the filtering layer in more detail.
Ubuntu also maintains official <a href=”https://documentation.ubuntu.com/server/how-to/security/firewalls/” target=”_blank” rel=”noopener”>firewall documentation</a> covering firewall configuration on Ubuntu Server.
Do not disable the firewall merely to make a multi-NIC configuration work. Identify whether the relevant traffic is actually being blocked.
Reverse Path Filtering on Multi-Homed Servers
Another issue worth checking is reverse path filtering.
Inspect:
sysctl net.ipv4.conf.all.rp_filter
and:
sysctl net.ipv4.conf.enp1s0.rp_filter
sysctl net.ipv4.conf.enp2s0.rp_filter
Reverse path validation can interact with asymmetric network designs.
However, do not immediately solve the problem by setting everything to zero.
First establish whether the routing architecture is correct and whether rp_filter is actually contributing to packet loss.
For kernel-level documentation, see the Linux kernel’s <a href=”https://docs.kernel.org/networking/ip-sysctl.html” target=”_blank” rel=”noopener”>IP sysctl documentation</a>, which documents rp_filter and other IPv4 networking parameters.
DHCP Can Recreate a Default Route
A particularly confusing situation occurs when one interface uses DHCP.
You configure the desired route manually, reboot, and an unwanted default route returns.
Inspect:
ip route
You may find a route associated with DHCP.
The reason is that DHCP can supply much more than an IP address. It can also provide gateway and DNS information.
CorgiNetwork’s <a href=”https://corginetwork.com/dhcp-explained/“>DHCP Explained</a> guide covers how DHCP configuration reaches clients.
In a multi-NIC design, determine exactly which component creates each default route.
DNS Problems Can Look Like Routing Problems
Suppose:
curl https://example.com
fails.
Before assuming policy routing is broken, check resolution:
getent ahosts example.com
or:
dig example.com
For the underlying resolution process, see CorgiNetwork’s <a href=”https://corginetwork.com/dns-explained/“>DNS Explained</a> guide.
When testing routing specifically, using a known destination IP can temporarily remove DNS from the equation.
Then return to hostname testing once IP connectivity is established.
Cloud Servers Require Two Levels of Routing Analysis
On a cloud VM, Netplan represents only part of the network.
A simplified path might be:
Ubuntu application
↓
Linux routing
↓
Virtual NIC
↓
Cloud subnet
↓
Cloud route table
↓
Security controls
↓
NAT / Internet gateway
↓
Internet
Therefore:
ip route
can be completely correct while the overall path still fails.
CorgiNetwork’s <a href=”https://corginetwork.com/cloud-networking-explained/“>Cloud Networking Explained</a> provides the conceptual bridge between operating-system networking and virtual cloud networks.
If you are comparing cloud implementations, see <a href=”https://corginetwork.com/aws-vs-azure-vs-google-cloud/“>AWS vs Azure vs Google Cloud</a>.
For provider-specific networking, prefer the official documentation for your platform, such as <a href=”https://docs.aws.amazon.com/vpc/” target=”_blank” rel=”noopener”>Amazon VPC documentation</a>, <a href=”https://learn.microsoft.com/en-us/azure/virtual-network/” target=”_blank” rel=”noopener”>Azure Virtual Network documentation</a>, or <a href=”https://cloud.google.com/vpc/docs” target=”_blank” rel=”noopener”>Google Cloud VPC documentation</a>.
Practical Troubleshooting Workflow
When an Ubuntu server with multiple interfaces behaves unpredictably, use this sequence.
1. Identify interfaces
ip -br link
2. Identify addresses
ip -br addr
3. Inspect the main routing table
ip route
4. Inspect policy rules
ip rule
5. Inspect all tables
ip route show table all
6. Ask the kernel which route it will use
ip route get DESTINATION_IP from SOURCE_IP
7. Test ICMP from each source
ping -I SOURCE_IP DESTINATION_IP
8. Test TCP
nc -vz DESTINATION 443
9. Test an application protocol
curl --interface SOURCE_IP https://example.com/
10. Capture packets
sudo tcpdump -ni any host DESTINATION_IP
This sequence moves the investigation from:
“My second interface doesn’t work.”
to:
“Linux selects table 200 correctly, sends the SYN through enp2s0, but no SYN-ACK returns.”
That is a much more actionable diagnosis.
Common Netplan Multiple-Route Mistakes
1. Adding Two Gateways Without Defining the Intended Behavior
Before configuring routes, decide whether you need:
- preference;
- failover;
- source separation;
- load distribution;
- access to separate private networks.
Those are different networking problems.
2. Assuming Metrics Solve Source Routing
Metrics primarily establish route preference.
They do not automatically guarantee that traffic sourced from each NIC always returns through that NIC’s gateway.
3. Looking Only at ip route
Once policy routing exists, also inspect:
ip rule
and:
ip route show table all
4. Applying Changes Directly Over SSH
A malformed route can immediately remove remote access.
Use:
sudo netplan try
and maintain console access whenever possible.
5. Ignoring Automatically Generated Routes
DHCP, cloud-init, NetworkManager, VPN software and container platforms can all affect routing.
6. Treating Ping as Proof That Everything Works
ICMP connectivity does not prove that TCP, HTTPS or application traffic follows the correct path.
Use tools appropriate to the layer being tested.
Production Checklist
Before considering the configuration finished, verify:
Interfaces
ip -br addr
Main routes
ip route
Policy rules
ip rule
Custom tables
ip route show table 100
ip route show table 200
Route selection
ip route get DESTINATION from SOURCE
TCP connectivity
nc -vz DESTINATION PORT
Actual packet path
sudo tcpdump -ni any host DESTINATION
Finally, verify that the configuration survives a reboot during an appropriate maintenance window.
Persistent configuration matters just as much as immediate connectivity.
Frequently Asked Questions
Can Ubuntu have two default gateways?
Yes. Linux can maintain multiple default routes. The important question is how the system should select between them. Metrics, separate routing tables and policy rules provide different mechanisms for controlling that behavior.
What does a Netplan route metric do?
It assigns a preference value to a route. When otherwise competing routes are available, lower metrics generally represent more-preferred routes.
What is Netplan routing-policy?
It allows Netplan to define Linux policy-routing rules that select routing tables according to matching criteria such as source or destination addresses. See the <a href=”https://netplan.readthedocs.io/en/stable/netplan-yaml/” target=”_blank” rel=”noopener”>official Netplan YAML reference</a> for the current syntax.
When should I use policy routing instead of metrics?
Metrics are useful when the requirement is primarily route preference. Policy routing is useful when different traffic—such as packets from different source addresses—must follow different routing tables.
How do I check which route Linux will actually use?
Run:
ip route get DESTINATION_IP
For source-based routing:
ip route get DESTINATION_IP from SOURCE_IP
Why does traffic enter through one NIC and leave through another?
The main routing table may prefer a different default route for the return destination. This can create asymmetric routing. Inspect ip rule, all routing tables and the result of ip route get.
Why does my second default route return after reboot?
It may be generated by Netplan, DHCP, NetworkManager, systemd-networkd, cloud-init or another networking component. Identify its source before attempting to remove it.
Can a firewall cause symptoms that look like incorrect routing?
Absolutely. Correct routes do not guarantee that packets are permitted. Inspect both Linux firewall rules and any upstream/cloud security controls.
Conclusion
Fixing Netplan multiple default routes is not primarily about finding the right YAML snippet. It is about defining the routing behavior the server actually requires.
If the requirement is:
Primary gateway
+
Backup gateway
route metrics may be enough.
If the requirement is:
Traffic from IP A → Gateway A
Traffic from IP B → Gateway B
you are dealing with source-based policy routing.
The most important diagnostic commands are:
ip addr
ip route
ip rule
ip route show table all
ip route get
Then use ping, nc, curl and tcpdump to verify what happens to real traffic.
The combination of Netplan configuration and Linux routing diagnostics provides a far more reliable solution than repeatedly changing default gateways until connectivity appears to work.
For your next troubleshooting step, CorgiNetwork’s <a href=”https://corginetwork.com/linux-network-tools-guide/“>Linux Network Tools Guide</a>, <a href=”https://corginetwork.com/netcat-explained/“>Netcat Explained</a>, and <a href=”https://corginetwork.com/wireshark-explained/“>Wireshark Explained</a> provide the tools needed to investigate the packet path from the command line all the way to packet-level analysis.