Mastering Single‑Host Container Networking: Namespaces, veth, Bridges & NAT
This tutorial explains how to build a functional single‑host container network on Linux by using network namespaces, virtual Ethernet pairs, a Linux bridge, IP routing, NAT with iptables, and port publishing, providing step‑by‑step commands and troubleshooting tips.
Background
Containers feel magical, but they are just isolated Linux processes. Understanding the underlying networking primitives—network namespaces, virtual Ethernet (veth) devices, bridges, routing, and NAT—is essential for reliable container networking on a single host.
Prerequisites
Any Linux distribution (the examples use a Vagrant CentOS 8 VM).
Docker or Podman for container runtime (the tutorial focuses on low‑level tools).
Inspecting the Host Network Stack
#!/usr/bin/env bash
echo "> Network devices"
ip link
echo -e "
> Route table"
ip route
echo -e "
> Iptables rules"
iptables --list-rulesRun the script after adding a simple iptables chain:
sudo iptables -N ROOT_NSCreating a Network Namespace
sudo ip netns add netns0
ip netns list # shows netns0Enter the namespace with nsenter:
sudo nsenter --net=/var/run/netns/netns0 bashConnecting a Namespace with a veth Pair
sudo ip link add veth0 type veth peer name ceth0
sudo ip link set ceth0 netns netns0
sudo ip link set veth0 up
sudo ip addr add 172.18.0.11/16 dev veth0 sudo nsenter --net=/var/run/netns/netns0
ip link set lo up
ip link set ceth0 up
ip addr add 172.18.0.10/16 dev ceth0Verify that the namespace sees only its own loopback device and the ceth0 interface.
Testing Connectivity
# From netns0 ping the host side of the veth pair
ping -c 2 172.18.0.11
# From the host ping the namespace side
ping -c 2 172.18.0.10Both pings succeed, confirming the veth tunnel works.
Adding a Second Container – Routing Conflict
Repeating the same steps for a second namespace ( netns1) creates another veth pair ( veth1/ceth1) with IPs 172.18.0.21/16 and 172.18.0.20/16. Ping between netns1 and the host fails because the host now has two identical routes for 172.18.0.0/16. Deleting the first route resolves the conflict but breaks connectivity for the first container.
Solution: Use a Linux Bridge
Instead of separate veth pairs, attach both veth0 and veth1 to a bridge ( br0) so the kernel can forward L2 frames between them.
sudo ip link add br0 type bridge
sudo ip link set br0 up
sudo ip link set veth0 master br0
sudo ip link set veth1 master br0Assign an IP to the bridge to act as the default gateway for the containers:
sudo ip addr add 172.18.0.1/16 dev br0Enabling Inter‑Namespace Routing
# Inside each namespace, set the default route via the bridge IP
sudo nsenter --net=/var/run/netns/netns0
ip route add default via 172.18.0.1
sudo nsenter --net=/var/run/netns/netns1
ip route add default via 172.18.0.1Now all containers can reach each other, the host, and the external network (once forwarding is enabled).
Enable IP Forwarding on the Host
sudo bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'Network Address Translation (NAT)
To allow containers to reach the Internet, masquerade their traffic:
sudo iptables -t nat -A POSTROUTING -s 172.18.0.0/16 ! -o br0 -j MASQUERADEAfter adding the rule, ping 8.8.8.8 from a namespace succeeds.
Port Publishing (DNAT)
Expose a container service (e.g., a Python HTTP server on 172.18.0.10:5000) on the host’s external IP ( 10.0.2.15) with:
# For traffic arriving from other hosts
sudo iptables -t nat -A PREROUTING -d 10.0.2.15 -p tcp --dport 5000 -j DNAT --to-destination 172.18.0.10:5000
# For locally generated traffic
sudo iptables -t nat -A OUTPUT -d 10.0.2.15 -p tcp --dport 5000 -j DNAT --to-destination 172.18.0.10:5000Load the br_netfilter module so the bridge participates in iptables processing:
sudo modprobe br_netfilterDocker Network Drivers Overview
Docker provides three main network modes:
host : No network namespace isolation; the container shares the host stack.
none : Only a loopback interface is present.
bridge (default): Implements the veth‑bridge setup described above.
Inspecting ip link and iptables from both host and container shows the corresponding rules.
Rootless Containers
Rootless runtimes (e.g., Podman) cannot create veth devices without root privileges. They fall back to slirp4netns, which uses a user‑space TCP/IP stack connected via a TAP device. This approach lacks raw‑socket capabilities, so tools like ping do not work inside rootless containers.
Conclusion
The tutorial demonstrates a practical, low‑level method for building single‑host container networks using Linux namespaces, veth pairs, a bridge, routing, NAT, and port publishing. While many higher‑level solutions exist, they all rely on the same kernel networking primitives, making this knowledge fundamental for cloud‑native and container‑oriented development.
References
https://docs.docker.com/network/#network-drivers
https://www.redhat.com/sysadmin/container-networking-podman
https://github.com/rootless-containers/slirp4netns
https://developers.redhat.com/blog/2018/10/22/introduction-to-linux-interfaces-for-virtual-networking/
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
