ip netns and vethModern Linux networking can do far more than assign IP addresses to physical interfaces.
A single Linux machine can host multiple independent network environments, each with its own interfaces, IP addresses, routing tables, sockets, and firewall rules.
This capability is provided by Linux network namespaces.
Network namespaces are one of the fundamental technologies behind container networking, network labs, VPN isolation, virtual routers, security testing environments, and advanced Linux network architectures.
If you have already worked through CorgiNetwork’s Linux Policy Routing with ip rule and Multiple Routing Tables and Linux VRF guides, network namespaces represent the next logical step.
Policy routing separates routing decisions.
VRF creates explicit Layer 3 routing domains.
Network namespaces go further by creating independent instances of major networking resources.
In this practical guide, we will build two network namespaces, connect them using a veth pair, configure IP addressing and routing, test communication, provide Internet connectivity, capture packets, and troubleshoot the most common namespace networking failures.
A network namespace creates an isolated instance of Linux networking resources for the processes using that namespace.
Conceptually, instead of every process sharing:
Linux Host
|
Network Stack
|
Interfaces
|
Routes you can create:
Linux Host
/ \
Namespace A Namespace B
| |
Network Stack Network Stack
| |
Routes Routes
| |
Interfaces Interfaces Processes operating inside Namespace A see a different networking environment from processes operating inside Namespace B.
The Linux manual documents network namespaces as isolating resources including network devices, IPv4 and IPv6 protocol stacks, IP routing tables, firewall rules, /proc/net, /sys/class/net, network-related sysctls, ports and sockets.
That makes network namespaces significantly broader than simply adding another routing table.
A network namespace can provide independent networking resources including:
Network interfaces
IPv4 networking stack
IPv6 networking stack
Routing tables
Firewall rules
Socket/port space
Network sysctls
/proc/net
/sys/class/net Imagine two applications:
Application A
↓
Namespace BLUE
↓
10.10.10.2
↓
Default Route A and:
Application B
↓
Namespace RED
↓
10.20.20.2
↓
Default Route B Both applications can run on the same Linux host while seeing substantially independent networking environments.
This capability is one reason namespaces became such an important building block for Linux container networking.
Network namespaces and VRFs can both separate network behavior, but they operate at different scopes.
A VRF primarily provides:
Layer 3 routing separation Conceptually:
VRF BLUE
↓
Routing Table 100 while:
VRF RED
↓
Routing Table 200 Network namespaces provide broader separation:
Namespace BLUE
↓
Interfaces
Routing tables
Firewall
Sockets
Network stack A simplified comparison:
| Feature | VRF | Network Namespace |
|---|---|---|
| Separate routing domain | Yes | Yes |
| Separate interfaces | Logical membership | Yes |
| Separate routing tables | Yes | Yes |
| Separate socket space | More limited | Yes |
| Separate firewall context | Not equivalent | Yes |
| Container-style networking | Limited role | Fundamental building block |
Use VRF when explicit Layer 3 routing domains are the primary requirement.
Use namespaces when you need broader network-stack isolation.
For the routing-domain approach, see CorgiNetwork’s Linux VRF Explained: Isolated Routing Tables with iproute2 guide.
Policy routing works differently.
Suppose a host contains:
192.168.10.20
10.20.30.20 You can use:
ip rule to decide which routing table traffic should use.
Conceptually:
Packet
↓
ip rule
↓
Table 100 or Table 200 That does not create an entirely separate network stack.
A namespace does:
Process
↓
Network Namespace
↓
Independent networking environment Therefore, use Linux Policy Routing when the routing decision itself is the primary problem.
Use namespaces when isolation of the networking environment is required.
A VLAN provides primarily Layer 2 segmentation.
A network namespace isolates Linux networking resources.
They can be combined.
For example:
Physical NIC
|
VLAN 10
|
Namespace BLUE and:
Physical NIC
|
VLAN 20
|
Namespace RED These technologies solve different problems and frequently complement one another.
Creating namespaces is easy.
Connecting them is the interesting part.
One of the most important tools is a virtual Ethernet pair, normally called a veth pair.
Think of it as a virtual Ethernet cable:
veth-a <================> veth-b Packets entering one end emerge from the other.
This makes veth pairs ideal for connecting:
The Linux network-namespace documentation specifically identifies veth pairs as a pipe-like abstraction that can connect namespaces.
We will create:
Linux Host
|
+---------+---------+
| |
ns-blue ns-red
| |
veth-blue ========= veth-red
| |
10.10.10.1 10.10.10.2 The goal is simple:
ns-blue
↓
10.10.10.1
↓
veth pair
↓
10.10.10.2
↓
ns-red This gives us a clean environment for learning how namespace networking actually works.
Run:
ip netns list or:
ip netns If no named network namespaces exist, the output may be empty.
The ip-netns(8) interface manages named network namespaces and stores the conventional namespace references under:
/var/run/netns/ Run:
sudo ip netns add ns-blue Verify:
ip netns list You should now see:
ns-blue At this point, Linux has created a separate network namespace.
But it does not yet have a useful external interface.
Create the second environment:
sudo ip netns add ns-red Verify again:
ip netns list Expected conceptually:
ns-red
ns-blue We now have:
Linux Host
|
+--- ns-blue
|
+--- ns-red But they are not connected.
Run:
sudo ip netns exec ns-blue ip link Then:
sudo ip netns exec ns-red ip link You will typically find a loopback device:
lo but it may initially be down.
Bring it up inside BLUE:
sudo ip netns exec ns-blue ip link set lo up Then RED:
sudo ip netns exec ns-red ip link set lo up Check:
sudo ip netns exec ns-blue ip -br link and:
sudo ip netns exec ns-red ip -br link This is your first demonstration that each namespace sees its own interfaces.
Now create our virtual cable:
sudo ip link add veth-blue type veth peer name veth-red Inspect:
ip link Both ends initially exist in the host namespace.
Conceptually:
Host namespace
veth-blue <==========> veth-red Next we move them.
Run:
sudo ip link set veth-blue netns ns-blue Now:
ns-blue
|
veth-blue
Host
|
veth-red If you run:
ip link from the host, veth-blue will no longer appear there because the device now belongs to another network namespace.
A physical or virtual interface belongs to a particular network namespace at a time.
Run:
sudo ip link set veth-red netns ns-red Now the topology becomes:
ns-blue ns-red
| |
veth-blue <===================> veth-red The host’s normal:
ip link will no longer show either interface.
Instead inspect:
sudo ip netns exec ns-blue ip link and:
sudo ip netns exec ns-red ip link Configure BLUE:
sudo ip netns exec ns-blue \
ip addr add 10.10.10.1/24 dev veth-blue Configure RED:
sudo ip netns exec ns-red \
ip addr add 10.10.10.2/24 dev veth-red Now:
ns-blue ns-red
10.10.10.1 10.10.10.2
| |
veth-blue <====================> veth-red BLUE:
sudo ip netns exec ns-blue \
ip link set veth-blue up RED:
sudo ip netns exec ns-red \
ip link set veth-red up Verify:
sudo ip netns exec ns-blue ip -br addr and:
sudo ip netns exec ns-red ip -br addr You should now have functioning Layer 3 endpoints.
Inside BLUE:
sudo ip netns exec ns-blue ip route You should see a connected route similar to:
10.10.10.0/24 dev veth-blue Now RED:
sudo ip netns exec ns-red ip route Again:
10.10.10.0/24 dev veth-red Notice what happened.
The host has its own routing table.
BLUE has its own.
RED has its own.
Conceptually:
HOST
└── routing table
ns-blue
└── routing table
ns-red
└── routing table This is much stronger isolation than simply creating custom tables with:
ip route ... table 100 From BLUE:
sudo ip netns exec ns-blue ping 10.10.10.2 You should receive replies from RED.
Then test the opposite direction:
sudo ip netns exec ns-red ping 10.10.10.1 If successful:
ns-blue
10.10.10.1
|
| ICMP
↓
10.10.10.2
ns-red Your isolated network works.
ip netns exec: One of the Most Important CommandsThe command:
ip netns exec NAME COMMAND executes a command inside a named network namespace.
For example:
sudo ip netns exec ns-blue bash Now the shell operates using the networking environment associated with BLUE.
Inside it, run:
ip addr then:
ip route then:
ss -lnt Exit with:
exit This technique is extremely useful for debugging.
Suppose you want a web server isolated inside BLUE.
You could run:
sudo ip netns exec ns-blue \
python3 -m http.server 8080 Now the process uses the network environment of:
ns-blue Another process running in RED can attempt to reach it:
sudo ip netns exec ns-red \
curl http://10.10.10.1:8080/ This demonstrates one of the most important namespace concepts:
Process
↓
Namespace
↓
Networking environment Processes normally inherit their network namespace from their parent.
This matters because applications launched with:
ip netns exec operate within the selected namespace’s networking context.
Conceptually:
ip netns exec ns-blue bash
↓
bash
↓
child process
↓
ns-blue This allows an entire application tree to operate using the isolated network.
The previous example connects:
namespace ↔ namespace Another extremely common architecture is:
namespace ↔ host Create:
sudo ip netns add ns-app Then create:
sudo ip link add veth-host type veth peer name veth-app Move one side:
sudo ip link set veth-app netns ns-app Now:
Linux Host ns-app
| |
veth-host <===============> veth-app Run:
sudo ip addr add 10.200.1.1/24 dev veth-host Bring it up:
sudo ip link set veth-host up Run:
sudo ip netns exec ns-app \
ip addr add 10.200.1.2/24 dev veth-app Then:
sudo ip netns exec ns-app \
ip link set veth-app up Bring loopback up:
sudo ip netns exec ns-app \
ip link set lo up Now:
HOST
10.200.1.1
|
veth-host
||
||
veth-app
|
10.200.1.2
ns-app Test from the namespace:
sudo ip netns exec ns-app ping 10.200.1.1 If the host will operate as the namespace’s router, add:
sudo ip netns exec ns-app \
ip route add default via 10.200.1.1 Inspect:
sudo ip netns exec ns-app ip route You should now see conceptually:
10.200.1.0/24 dev veth-app
default via 10.200.1.1 The packet path becomes:
ns-app
10.200.1.2
↓
default route
↓
10.200.1.1
↓
Linux host At this point the namespace can reach the host.
That does not automatically mean it can reach the Internet.
The host needs to route the traffic onward.
The architecture becomes:
ns-app
10.200.1.2
|
v
Linux Host
10.200.1.1
|
v
Host uplink
|
v
Internet Several components may be required:
IP forwarding
Firewall forwarding policy
NAT or upstream route
DNS Check:
sysctl net.ipv4.ip_forward If routing is intentionally required, it can be enabled at runtime:
sudo sysctl -w net.ipv4.ip_forward=1 Do not blindly enable forwarding on production machines without understanding the security consequences.
The host is now acting more like a router.
Firewall policy becomes important.
In a simple lab where the upstream network does not know how to route:
10.200.1.0/24 back toward the host, source NAT may be needed.
With nftables, the conceptual flow is:
10.200.1.2
↓
Host routing
↓
Source NAT
↓
Host Internet address
↓
Internet The exact nftables policy depends on your existing firewall configuration.
Do not flush or replace an existing production ruleset merely to add namespace connectivity.
Inspect first:
sudo nft list ruleset Then integrate the namespace network deliberately into your firewall design.
If the upstream router already knows:
10.200.1.0/24 is reachable through your Linux host, NAT may be unnecessary.
You can instead use normal routing.
This distinction is important:
NAT and:
routing are not the same thing.
Do not automatically add masquerading whenever a namespace cannot reach another network.
First understand the return path.
Ask the namespace:
sudo ip netns exec ns-app \
ip route get 8.8.8.8 This tells you which route the namespace itself intends to use.
If the result points toward:
10.200.1.1 the namespace routing configuration is probably correct.
Now investigate the host.
This is exactly the same evidence-based methodology used in CorgiNetwork’s Linux Traffic Uses the Wrong Interface guide.
Suppose:
sudo ip netns exec ns-app ping 8.8.8.8 works but:
sudo ip netns exec ns-app ping example.com fails.
That strongly suggests looking at DNS rather than routing first.
ip netns exec supports per-namespace configuration conventions under:
/etc/netns/NAME/ For example, a namespace-specific resolver configuration can be associated with:
/etc/netns/ns-app/resolv.conf This is particularly useful when:
Namespace A → DNS A
Namespace B → DNS B or when a namespace is being used to isolate VPN traffic.
Namespaces are excellent for VPN isolation.
Conceptually:
Application
↓
VPN Namespace
↓
VPN Interface
↓
VPN Gateway
↓
Internet while the rest of the host uses:
Host applications
↓
Normal routing table
↓
Normal gateway This can prevent an application from accidentally using the host’s ordinary network path.
A dedicated CorgiNetwork article can later expand this into a full Linux VPN Network Namespace Kill-Switch tutorial.
Namespaces are one of the Linux technologies underlying container isolation.
Linux provides several namespace types, including:
Network
Mount
PID
User
UTS
IPC
Cgroup
Time A container runtime can combine multiple namespace types so that processes perceive isolated system resources.
Network namespaces specifically provide the networking component.
Conceptually:
Container
|
+--- PID namespace
+--- Mount namespace
+--- Network namespace
+--- User namespace
+--- UTS namespace This is why understanding ip netns gives you a much deeper understanding of container networking.
Connecting only two namespaces is simple with one veth pair.
What if you need:
ns1
ns2
ns3
ns4 on the same virtual Ethernet network?
Use a Linux bridge.
Conceptually:
Linux Bridge
/ | \
/ | \
veth1 veth2 veth3
| | |
ns1 ns2 ns3 Each namespace gets one end of a veth pair.
The host-side ends connect to the bridge.
This architecture closely resembles a virtual Ethernet switch.
It is also an excellent foundation for a future CorgiNetwork article on Linux Bridge Networking with Network Namespaces.
Packet capture is one of the fastest ways to understand namespace problems.
Inside BLUE:
sudo ip netns exec ns-blue \
tcpdump -ni veth-blue Then generate traffic from RED:
sudo ip netns exec ns-red \
ping 10.10.10.1 You should see the packets inside BLUE’s namespace.
This lets you answer:
Did the packet arrive? rather than guessing.
For deeper analysis, continue with CorgiNetwork’s Wireshark Explained guide.
For the host-connected architecture:
ns-app
|
veth-app
|
veth-host
|
Host you can capture:
sudo tcpdump -ni veth-host while generating:
sudo ip netns exec ns-app ping 10.200.1.1 If packets appear on veth-host, the veth link is functioning.
Then move to the next layer:
Host routing
Firewall
NAT
Uplink Suppose:
sudo ip netns exec ns-app ping 8.8.8.8 fails.
Do not immediately modify firewall rules.
Start inside the namespace:
sudo ip netns exec ns-app ip -br addr Then:
sudo ip netns exec ns-app ip route Then:
sudo ip netns exec ns-app ip route get 8.8.8.8 Then test the namespace gateway:
sudo ip netns exec ns-app ping 10.200.1.1 Only after those checks should you move outward.
Use this model:
Application
↓
Namespace socket
↓
Namespace routing table
↓
veth interface
↓
Host veth interface
↓
Host routing
↓
Firewall
↓
NAT
↓
Physical interface
↓
Gateway Find the layer where packets disappear.
That is much more reliable than changing random settings.
You create a namespace and an application behaves strangely.
Check:
sudo ip netns exec ns-blue ip link show lo If necessary:
sudo ip netns exec ns-blue ip link set lo up Do not forget the namespace has its own loopback interface context.
Check BLUE:
sudo ip netns exec ns-blue ip link and RED:
sudo ip netns exec ns-red ip link Make sure both ends are up.
A perfectly configured IP address is useless if the interface itself is administratively down.
Check:
sudo ip netns exec ns-blue ip -br addr If veth-blue has no expected address, correct the addressing before troubleshooting routing.
Follow:
Link
↓
Address
↓
Route
↓
Firewall in that order.
Inside:
ns-app you may have:
10.200.1.0/24 dev veth-app but no:
default via 10.200.1.1 Then local communication works while Internet communication fails.
Inspect:
sudo ip netns exec ns-app ip route Never assume a default route exists.
This is extremely common.
If:
namespace → host works but:
namespace → Internet does not, investigate:
Host IP forwarding
Host firewall
Host route
NAT
Upstream return route The namespace itself may be configured perfectly.
Test:
sudo ip netns exec ns-app ping 8.8.8.8 and then:
sudo ip netns exec ns-app getent hosts example.com If the first succeeds and the second fails, inspect DNS.
Do not rewrite routing configuration to fix a resolver problem.
A multi-homed host may receive namespace traffic through one path but send return traffic somewhere unexpected.
Check:
ip route get DESTINATION and if policy routing exists:
ip rule Then inspect:
ip route show table all For complicated multi-interface routing, use the Linux Policy Routing guide.
rp_filterReverse-path filtering can become relevant when the host has multiple interfaces, asymmetric routing, policy routing, or unusual namespace topologies.
Check:
sysctl -a 2>/dev/null | grep '\.rp_filter' Do not simply disable it because packets are disappearing.
First understand the reverse route.
CorgiNetwork’s Linux rp_filter and Asymmetric Routing guide explains the strict, loose, and disabled modes and how they interact with multi-homed Linux systems.
For Ethernet-connected namespace architectures, neighbor discovery still matters.
Inspect:
ip neigh on the host.
Inside the namespace:
sudo ip netns exec ns-app ip neigh If several physical NICs share the same subnet and Linux responds unexpectedly to ARP requests, continue with Linux ARP Flux and Multiple NICs on the Same Subnet.
Namespaces do not make underlying Layer 2 behavior irrelevant.
Suppose the host has:
ISP A
ISP B while different namespaces need different uplinks.
You can combine namespaces with:
Policy routing
VRF
Firewall marks
Dedicated host routes depending on the architecture.
For Ubuntu multi-gateway environments, CorgiNetwork’s Netplan Multiple Default Routes and Policy Routing guide explains the persistent routing layer.
This creates a powerful architecture:
Application
↓
Namespace
↓
Host routing policy
↓
Routing table
↓
Selected ISP Use:
ip netns pids ns-blue This reports processes whose primary network namespace is the named namespace.
You can also run:
ip netns identify PID to identify a named namespace associated with a process when applicable.
These commands are useful when troubleshooting:
Which process is actually using this namespace? To delete:
sudo ip netns del ns-blue But be careful if processes are still using it.
Inspect:
ip netns pids ns-blue before cleanup.
The ip-netns(8) documentation notes that deleting the named reference does not necessarily immediately destroy a namespace if processes still hold it.
For controlled labs, terminate namespace processes before deleting the namespace.
A physical network device can belong to one network namespace.
When the namespace that owns it is eventually freed, Linux returns physical network devices to the initial network namespace.
Virtual veth devices behave differently: when the namespace containing them is destroyed, the relevant virtual devices are destroyed rather than becoming ordinary host interfaces.
This distinction is important when designing cleanup procedures.
When a namespace cannot communicate, follow this sequence.
ip netns list sudo ip netns exec NAME ip -br link sudo ip netns exec NAME ip -br addr sudo ip netns exec NAME ip link show lo sudo ip netns exec NAME ip route sudo ip netns exec NAME \
ip route get DESTINATION sudo ip netns exec NAME ping GATEWAY sudo ip netns exec NAME ip neigh sudo ip netns exec NAME \
tcpdump -ni INTERFACE sudo tcpdump -ni HOST_VETH sysctl net.ipv4.ip_forward ip route ip rule
ip route show table all sudo nft list ruleset sudo ip netns exec NAME \
getent hosts example.com This gives you a repeatable evidence-driven troubleshooting process.
Namespace has no connectivity
|
v
Does namespace exist?
/ \
NO YES
| |
Create v
Interface exists?
/ \
NO YES
| |
Fix veth v
Interface UP?
/ \
NO YES
| |
Bring UP v
IP configured?
/ \
NO YES
| |
Add IP v
Route exists?
/ \
NO YES
| |
Add route v
Gateway reachable?
/ \
NO YES
| |
Check veth v
/neighbor Host forwarding?
/ \
NO YES
| |
Fix host v
Firewall/NAT/
upstream route Before using a network namespace architecture in production, verify:
✓ Namespace exists
✓ Loopback is up
✓ Correct interfaces belong to namespace
✓ veth peers are correctly connected
✓ Interfaces are UP
✓ IP addresses are correct
✓ Connected routes exist
✓ Default route is correct
✓ Namespace can reach its gateway
✓ Host forwarding is intentional
✓ Firewall rules are understood
✓ NAT is used only when required
✓ Upstream return path exists
✓ DNS works independently
✓ rp_filter behavior is understood
✓ Packet captures confirm the path
✓ Processes actually run in intended namespace
✓ Persistent configuration is defined
✓ Recovery access exists Do not consider the architecture complete merely because:
ping works Test the actual application.
A Linux network namespace isolates networking resources so that processes in different namespaces can have independent interfaces, routing tables, firewall rules, sockets, and network-stack state.
Use:
sudo ip netns add ns-blue Then verify:
ip netns list Use:
sudo ip netns exec ns-blue COMMAND For example:
sudo ip netns exec ns-blue ip route A veth pair is a pair of virtual Ethernet interfaces where packets sent through one end appear at the other.
They are commonly used to connect network namespaces.
Create a veth pair:
sudo ip link add veth-a type veth peer name veth-b Move each end:
sudo ip link set veth-a netns ns-a
sudo ip link set veth-b netns ns-b Then assign addresses and bring the interfaces up.
Yes. Network namespaces isolate IP routing tables as part of their independent networking environment.
Network namespaces isolate firewall-rule context along with other networking resources.
No.
VRF primarily creates Layer 3 routing-domain separation.
Network namespaces provide broader network-stack isolation.
Yes. Linux namespaces are fundamental building blocks used by container technologies to isolate resources. Network namespaces provide the network-isolation component.
Check:
default route
host IP forwarding
host firewall
NAT
upstream return route The veth connection may be working even though forwarding beyond the host is not.
That usually points toward DNS configuration rather than basic IP routing.
Check the resolver configuration associated with the namespace.
Use:
ip netns pids NAME Run:
sudo ip netns exec NAME \
tcpdump -ni INTERFACE Yes.
Linux networking allows VRFs to exist within network namespaces, enabling multiple levels of network organization and isolation.
Linux network namespaces transform a single Linux machine into a platform capable of hosting multiple isolated network environments.
The fundamental architecture is:
Process
↓
Network Namespace
↓
Interfaces
↓
Routing Table
↓
Firewall
↓
Network With veth pairs, those isolated environments can then be connected:
Namespace A
|
veth-a
||
||
veth-b
|
Namespace B or connected to the host:
Namespace
↓
veth
↓
Linux Host
↓
Routing / NAT
↓
Internet The essential commands to remember are:
ip netns list
ip netns add NAME
ip netns exec NAME COMMAND
ip netns pids NAME
ip link add ... type veth peer name ...
ip link set INTERFACE netns NAME
ip netns del NAME But commands alone are not enough.
The real skill is understanding the packet path.
If the problem is primarily choosing between multiple routing tables, continue with CorgiNetwork’s Linux Policy Routing with ip rule and Multiple Routing Tables.
If the system needs explicit Layer 3 routing domains without broader network-stack isolation, use the Linux VRF Explained guide.
If Linux sends packets through an unexpected NIC, use Linux Traffic Uses the Wrong Interface.
For Ubuntu servers with multiple default gateways, see Netplan Multiple Default Routes and Policy Routing.
If reverse-path validation interferes with asymmetric traffic, continue with Linux rp_filter and Asymmetric Routing.
And for systems with multiple NICs on the same subnet, see Linux ARP Flux and Multiple NICs on the Same Subnet.
This extends the CorgiNetwork advanced Linux networking cluster into a clear progression:
Wrong Interface
↓
Multiple Default Routes
↓
ARP Flux
↓
Asymmetric Routing / rp_filter
↓
Policy Routing
↓
Multiple Routing Tables
↓
Linux VRF
↓
Network Namespaces
↓
veth Networking
↓
Container Networking The next natural layer is Linux Bridge Networking with Network Namespaces and veth, where several isolated namespaces are connected through a Linux software bridge to build a complete virtual Layer 2 network.
AI Agents as Code: Managing AI Agent Configurations, Prompts and Tools with Git AI agents…
Data Center Power Distribution Architecture: UPS, PDU, Redundancy and Rack Power Explained Data center power…
DNSSEC Troubleshooting: Fix SERVFAIL & DNSKEY Errors DNSSEC Troubleshooting: How to Fix SERVFAIL, DS, DNSKEY…
Terraform State Management Explained: Remote State, Locking, Backends and Best Practices Terraform makes infrastructure reproducible…
RTO vs RPO Explained: Disaster Recovery Objectives, Examples and Planning A disaster recovery plan is…
Network Intrusion Detection Explained: NIDS, Sensors, Signatures and Traffic Analysis A firewall can decide whether…