How to Build an Isolated Single‑Host Container Network with Linux Namespaces, veth, and Bridge
This tutorial walks through creating a fully isolated container network on a single Linux host using network namespaces, virtual Ethernet (veth) pairs, a Linux bridge, IP routing, NAT with iptables, and port publishing, covering both root and rootless container scenarios.
Introduction
Containers feel magical, but understanding the underlying Linux networking primitives—network namespaces, virtual Ethernet devices (veth), bridges, routing, and NAT—lets you build reliable, isolated networks without relying on Docker’s default magic.
Prerequisites
Any Linux distribution works; the examples run on a Vagrant CentOS 8 VM. The tutorial uses Docker or Podman for container execution, but the focus is on the low‑level networking tools.
$ vagrant init centos/8
$ vagrant up
$ vagrant ssh
$ uname -a
Linux localhost.localdomain 4.18.0-147.3.1.el8_1.x86_64Network‑Namespace Isolation
Linux network namespaces provide a separate network stack (interfaces, routes, firewall rules). Create one with ip netns add netns0 and inspect it using a small script.
#!/usr/bin/env bash
echo "> Network devices"
ip link
echo -e "
> Route table"
ip route
echo -e "
> Iptables rules"
iptables --list-rulesBefore running the script, add a custom chain to avoid conflicts: $ sudo iptables -N ROOT_NS Running the script shows the default loopback and eth0 devices, the default routing table, and the newly added chain.
Connecting a Container with a veth Pair
Create a paired veth device, move one end into the namespace, and assign IP addresses:
$ sudo ip link add veth0 type veth peer name ceth0
$ sudo ip netns add netns0
$ 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 bash -c '
ip link set lo up
ip link set ceth0 up
ip addr add 172.18.0.10/16 dev ceth0
ip route
'Ping tests confirm that the namespace sees a distinct network stack and can communicate with its peer:
# Inside netns0
$ ping -c 2 172.18.0.11
# Inside root namespace
$ ping -c 2 172.18.0.10Scaling to Multiple Containers – The Bridge Solution
When several containers share the same IP subnet, simple veth routing collides. Using a Linux bridge (L2 switch) solves this:
$ 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 br0After moving both containers’ peer ends (ceth0, ceth1) into their namespaces and assigning IPs, the containers can ping each other through the bridge.
Connecting the Bridge to the Host and the Outside World
Assign an IP to the bridge interface so the host can reach the containers: $ sudo ip addr add 172.18.0.1/16 dev br0 Enable IP forwarding on the host:
sudo bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'Configure NAT so containers can reach external networks:
$ sudo iptables -t nat -A POSTROUTING -s 172.18.0.0/16 ! -o br0 -j MASQUERADENow containers can ping 8.8.8.8 and the host can ping the containers.
Publishing Container Ports to the Host
Expose a service running inside a container (e.g., a Python HTTP server on 172.18.0.10:5000) to the host’s external IP (10.0.2.15) using DNAT rules:
# For traffic arriving on the host
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:5000
# Allow bridge traffic to be filtered
sudo modprobe br_netfilterAfter adding the rules, curl 10.0.2.15:5000 returns the container’s HTTP response.
Understanding Docker Network Drivers
Docker’s built‑in drivers map directly to the primitives demonstrated:
--network host : No namespace isolation; container shares the host’s stack.
--network none : Only a loopback interface, similar to a freshly created namespace without veth devices.
--network bridge (default): Implements the bridge‑based setup described above.
Rootless Containers
Rootless Podman uses slirp4netns to provide user‑space networking without requiring root privileges. While functional, rootless containers lack raw socket capabilities (e.g., ping) and cannot create veth pairs directly.
Conclusion
The article presents one of the most common ways to wire containers on a single host using Linux network namespaces, veth pairs, a bridge, routing, and NAT. Although many alternative plugins exist, they all rely on the same underlying Linux networking features, making this knowledge essential for any container‑oriented workflow.
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.
