After you add a second network interface, SSH or a website may become unreachable from the internet even though requests appear in a packet capture. Sometimes one server IP works while another times out. Before adding another default route or disabling rp_filter, establish where the connection stops.
A useful clue is a request arriving on one interface while the reply leaves through another. Reverse path filtering, source-based policy routing, and upstream source-address checks can all affect the result. This guide follows three questions: did the request arrive, where does the reply go, and could filtering reject it?
This guide covers Linux IPv4. Interface names, addresses, and routing-table numbers are examples, not a production configuration to paste unchanged. For cloud servers, containers, and VRFs, inspect the network context that actually carries the service traffic. References checked: September 9, 2026.
1. Establish the failure scope before changing kernel settings
Record the affected client IP, the server's actual local IP, the service port, and the time of failure. Then inspect interface addresses, listening sockets, and routing rules:
date -Is ip -br address ip -4 rule show ip -4 route show table all ss -lntp
These commands inspect state without changing network configuration. Showing processes owned by other users with ss may require additional privileges. Check the following:
Is each interface in the expected state, with the correct IP address and prefix length?
Is the service listening on the target IP or an appropriate wildcard address? Changing a default route will not make a service bound only to 127.0.0.1 reachable from outside.
Do existing rules select routing tables by source address, fwmark, or other conditions?
Are there multiple default routes, and which tables and metrics do they use?
Within the same routing table and otherwise equivalent matches, a lower metric is generally preferred. However, route selection also involves rule priority and longest-prefix matching. Default-route metrics alone do not explain every flow. Rules with lower numerical priority values are examined earlier. [2][3]
If incoming packets never reach the server, first check DNS, load balancers, cloud security groups, network ACLs, and the upstream path. Setting rp_filter to 0 will not normally fix a failure before the packet reaches the host.
2. Check the return route using the actual source address
Consider this example, which uses documentation-only IP addresses:
eth0: 192.0.2.10/24, gateway 192.0.2.1.
eth1: 198.51.100.10/24, gateway 198.51.100.1.
External test client: 203.0.113.50.
The client connects to the service on eth1's address, so the server's reply should use source address 198.51.100.10.
A route lookup without a source address may not represent this connection. Query the relevant source and destination:
ip -4 route get 203.0.113.50 from 198.51.100.10
The dev, via, and table information in the output helps identify the selected interface, gateway, and routing table. [2]
If the result uses eth0 but the service must return through eth1's provider, that is evidence of a return-path mismatch. This command only performs a route lookup with the supplied conditions. It is not an end-to-end connectivity test and does not prove that a packet was transmitted.
If the design uses fwmark, a VRF, or port-based routing, include the relevant conditions. For example, if the actual service traffic uses mark 0x1:
ip -4 route get 203.0.113.50 from 198.51.100.10 mark 0x1
Do not invent a mark for the test. First establish how the firewall, connection-mark handling, or application sets and restores it. Otherwise, the query may describe a different path from the failing traffic.
3. Capture the same connection on both interfaces
Use two terminals to observe eth0 and eth1 during a controlled connection attempt:
sudo tcpdump -nn -i eth0 -c 100 'host 203.0.113.50 and tcp port 443' sudo tcpdump -nn -i eth1 -c 100 'host 203.0.113.50 and tcp port 443'
Replace the client IP, port, and interfaces with the real values. The -nn option avoids address and port-name resolution. The -c 100 option limits the packet count, not elapsed time: if too few matching packets arrive, stop the capture with Ctrl+C after the test. [4]
Use the observed handshake to narrow the investigation:
No incoming SYN on either interface: verify the capture location and filter, then investigate the upstream path.
SYN arrives on eth1 but no response appears: inspect the listener, host firewall, reverse path filtering, and local network-stack processing. This observation alone does not establish that rp_filter is responsible.
SYN arrives on eth1 but SYN-ACK leaves through eth0: the return interface differs from the ingress interface. Check whether this is intentional and whether the upstream network permits that source address on the selected exit.
SYN arrives on eth1 and SYN-ACK also leaves through eth1, but no client ACK returns: continue with upstream return routing, NAT, firewalls, and the client side instead of repeatedly changing the listener.
Seeing a packet in a capture does not prove that the application received it. Asymmetric routing is not inherently wrong: some networks support different inbound and outbound paths. What matters is whether filtering policies, NAT state, and upstream routing support the design. [1][5]
Limit capture scope and duration rather than collecting all production payloads. Remove customer addresses, domains, and sensitive information before sharing results.
4. Understand rp_filter values 0, 1, and 2
The rp_filter setting controls IPv4 source validation using reverse-path checks. The Linux kernel documentation defines these modes: [1]
0: no source validation by this mechanism.
1: strict mode. If the best reverse path to the packet's source does not use the incoming interface, packets that fail the check are discarded by default.
2: loose mode. A source reachable through any interface does not fail this check merely because the reverse interface differs. A source that is not reachable still fails validation.
Read the current settings first. These examples use eth0 and eth1:
sysctl net.ipv4.conf.all.rp_filter sysctl net.ipv4.conf.eth0.rp_filter sysctl net.ipv4.conf.eth1.rp_filter
The effective value for an interface is the numerical maximum of the all setting and that interface's setting. [1]
For example, all=1 with eth1=0 does not disable filtering on eth1. With all=1 and eth1=2, loose mode applies. A larger number is not necessarily stricter: mode 2 is loose, not a stronger version of mode 1.
The kernel documentation lists a default of 0, but distribution startup scripts or other network configuration can change it. Inspect the running values instead of assuming defaults from a tutorial. IPv4 rp_filter is also not a general-purpose fix for IPv6 connectivity.
Test loose mode only when the evidence supports it
Consider a temporary change on the affected interface only if the evidence points to strict reverse path validation, asymmetric routing is intentional, and you retain cloud-console access or another recovery channel. Record the original values first:
sysctl -n net.ipv4.conf.all.rp_filter sysctl -n net.ipv4.conf.eth1.rp_filter
Then run the controlled temporary test:
sudo sysctl -w net.ipv4.conf.eth1.rp_filter=2
Repeat the connection from the same external client and inspect the captures. If it does not help, restore the interface value you recorded. The following rollback is correct only if the original value really was 1:
sudo sysctl -w net.ipv4.conf.eth1.rp_filter=1
This is not a recommendation to set every dual-NIC server to mode 2 or disable anti-spoofing checks globally. Even if connectivity returns, investigate whether the original routes were wrong. Loose mode relaxes the interface constraint, so assess the change alongside network-edge source validation and access controls. [1][5]
5. Test source-based policy routing for a specific return path
If replies sourced from eth1's address must leave through eth1's gateway, evaluate source-based policy routing instead of repeatedly adding default routes to the main table. [2][3]
The following test is deliberately restricted to the single test client above. Before running it, verify that the addresses and gateway are real and reachable, table 101 is unused, priority 11010 is available, and earlier rules will not match first. Keep your management connection separate from the client path being tested.
Inspect the proposed table and the existing rules:
ip -4 rule show ip -4 route show table 101
Only after confirming that table 101 can be dedicated to this test, add the temporary configuration:
sudo ip -4 route add table 101 198.51.100.0/24 dev eth1 src 198.51.100.10 sudo ip -4 route add table 101 default via 198.51.100.1 dev eth1 sudo ip -4 rule add priority 11010 from 198.51.100.10/32 to 203.0.113.50/32 lookup 101
ip -4 route get 203.0.113.50 from 198.51.100.10
The connected-subnet route is added first so that this table can resolve the example gateway. The default route follows, and the rule sends only the specified source-to-client traffic to table 101. This example assumes an ordinary Ethernet topology with a directly connected gateway. Cloud-specific gateway and routing constraints require environment-specific treatment.
If any command fails, stop and investigate. Do not casually change add to replace and overwrite an existing configuration. After testing, remove only the objects that were successfully added. If all three additions succeeded, roll them back in this order:
sudo ip -4 rule del priority 11010 from 198.51.100.10/32 to 203.0.113.50/32 lookup 101 sudo ip -4 route del table 101 default via 198.51.100.1 dev eth1 sudo ip -4 route del table 101 198.51.100.0/24 dev eth1
Before extending the policy to every destination for this source address, account for management networks, internal networks, and any other specific routes. Simply removing the to condition does not make this a complete production configuration. After validation, persist the design through the network configuration system actually in use, such as NetworkManager, systemd-networkd, or the distribution's networking mechanism. Runtime commands alone are not persistent configuration.
6. Account for cloud NAT, CDN origin traffic, and packet marks
The public IP may not be assigned to the local interface
When a cloud platform maps a public address to a private address, ip address may show only the private address. Use the actual local source address of the service flow in route get, not a public IP that is not assigned to the host. Check cloud routes, NAT, and security policies as well as the operating system.
Visitor traffic and CDN origin traffic are separate connections
With a CDN, distinguish the visitor-to-edge path from the edge-to-origin path. For an origin connectivity investigation, choose the packet-capture peer according to the actual origin connection; do not automatically filter on the visitor's IP. A CDN origin timeout alone does not prove that Linux policy routing is incorrect.
Understand fwmark together with src_valid_mark
For marked routing, whether reverse-path validation includes the mark can change the result. According to the kernel documentation, src_valid_mark=0 excludes the packet's fwmark from the reverse-path lookup. A value of 1 includes it, supporting designs that use the mark for routing in both directions. [1]
Inspect the current configuration:
sysctl net.ipv4.conf.all.src_valid_mark sysctl net.ipv4.conf.eth1.src_valid_mark
This parameter also uses the maximum of the all and interface values. It is not a switch to enable on every policy-routing server. Designs such as transparent proxies that use marks in only one direction may require different handling. Establish when marks are set and whether connection marks are restored before changing it.
7. Verify the whole connection, not just ping
Keep before-and-after copies of the rules, route lookups, and relevant captures. Test a complete application request from the same external client that originally failed. Confirm that the target IP and port are still listening, incoming and return paths match the design, the TCP handshake and application response succeed, and management access and other addresses remain unaffected.
If you persist the changes, verify the result after a controlled network-configuration reload during a maintenance window. One successful ping is not enough. Do not troubleshoot by flushing all routes, clearing the firewall, or globally disabling rp_filter.
For a dual-NIC Linux server that is unreachable from outside, begin by connecting the evidence for one flow: its source address, ingress interface, routing rules, and return interface. Identify where the path departs from the intended design before deciding whether to fix routes, adjust filtering, or investigate the cloud platform and upstream network.
References
These references explain the parameters and commands; they do not mean the examples have been validated in your production environment. References checked: September 9, 2026.
Linux Kernel Documentation — IP Sysctl, including rp_filter and src_valid_mark: https://docs.kernel.org/networking/ip-sysctl.html
iproute2 upstream manual — ip-route(8), hosted by man7: https://man7.org/linux/man-pages/man8/ip-route.8.html
iproute2 upstream manual — ip-rule(8), hosted by man7: https://man7.org/linux/man-pages/man8/ip-rule.8.html
Official tcpdump manual: https://www.tcpdump.org/manpages/tcpdump.1.html
RFC 3704 — Ingress Filtering for Multihomed Networks: https://www.rfc-editor.org/rfc/rfc3704.html