Cloud Native 31 min read

Master Single‑Host Container Networking with Linux Namespaces, veth and Bridges

This tutorial walks through building isolated, virtualized networking for containers on a single Linux host using network namespaces, virtual Ethernet pairs, Linux bridges, IP routing, NAT, and iptables rules, enabling inter‑container communication, host access, and external connectivity without writing any custom code.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Master Single‑Host Container Networking with Linux Namespaces, veth and Bridges

Using containers often feels magical; they are easy for those who understand the underlying principles but can be a nightmare for newcomers. Fortunately, containers are just isolated, limited Linux processes, and you can run them without images while building images requires running containers.

We now address single‑host container networking, answering four key questions:

How to virtualize network resources so each container thinks it has an exclusive network?

How to let containers coexist peacefully, avoid interference, and still communicate?

How to access external networks from inside a container?

How to expose a container's service to the outside world (port publishing)?

The solution relies on well‑known Linux features:

Network namespaces

Virtual Ethernet devices (veth)

Linux bridges

IP routing and NAT

No additional code is required to make this network magic work.

Prerequisites

Any Linux distribution works. All examples run on a Vagrant CentOS 8 VM:

$ vagrant init centos/8
$ vagrant up
$ vagrant ssh
[vagrant@localhost ~]$ uname -a
Linux localhost.localdomain 4.18.0-147.3.1.el8_1.x86_64

We use Docker or Podman as the container runtime and focus on the most basic tools.

Network namespace isolation

Linux’s network stack consists of devices, routing rules, and netfilter hooks (iptables). A simple script inspect-net-stack.sh shows the current state:

#!/usr/bin/env bash
 echo "> Network devices"
 ip link
 echo -e "
> Route table"
 ip route
 echo -e "
> Iptables rules"
 iptables --list-rules

Before running the script we create a custom chain:

$ sudo iptables -N ROOT_NS

Running the script now prints the host’s network devices, routes, and iptables rules, confirming that each future container will have its own isolated stack.

We create a network namespace using the ip netns command:

$ sudo ip netns add netns0
$ ip netns
netns0

To enter the namespace we use nsenter:

$ sudo nsenter --net=/var/run/netns/netns0 bash
# inside netns0, the network stack is empty

Connecting containers with virtual Ethernet (veth)

Linux provides veth pairs that act as a tunnel between two namespaces. Create a pair:

$ sudo ip link add veth0 type veth peer name ceth0

One end stays in the root namespace, the other is moved into netns0:

$ sudo ip link set ceth0 netns netns0

Bring the devices up and assign IP addresses:

$ 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"

Ping tests show that the two ends can reach each other:

# from netns0
ping -c 2 172.18.0.11
# from root namespace
ping -c 2 172.18.0.10

Routing tables reveal a single 172.18.0.0/16 route in each namespace pointing to the peer device.

Connecting multiple containers with a Linux bridge

When more than one container is attached to the same bridge, each container can communicate with the others at L2. First, clean up the previous setup:

$ sudo ip netns delete netns0
$ sudo ip netns delete netns1
$ sudo ip link delete veth0
$ sudo ip link delete ceth0
$ sudo ip link delete veth1
$ sudo ip link delete ceth1

Create two namespaces and their veth pairs without assigning IPs yet:

# netns0
sudo ip netns add netns0
sudo ip link add veth0 type veth peer name ceth0
sudo ip link set veth0 up
sudo ip link set ceth0 netns netns0
# netns1
sudo ip netns add netns1
sudo ip link add veth1 type veth peer name ceth1
sudo ip link set veth1 up
sudo ip link set ceth1 netns netns1

Create a bridge and attach both veth devices:

$ 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 br0

Assign IPs inside each namespace:

# netns0
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"
# netns1
sudo nsenter --net=/var/run/netns/netns1 bash -c "ip link set lo up && ip link set ceth1 up && ip addr add 172.18.0.20/16 dev ceth1"

Now the containers can ping each other:

# from netns0
ping -c 2 172.18.0.20
# from netns1
ping -c 2 172.18.0.10

Connecting the bridge to the host and the external world

Give the bridge an IP address so the host can reach the containers:

$ sudo ip addr add 172.18.0.1/16 dev br0

Now the host can ping both containers, and the containers can ping the host.

Enable IP forwarding on the host:

sudo bash -c 'echo 1 > /proc/sys/net/ipv4/ip_forward'

Set a default route inside each namespace pointing to the bridge:

# netns0
sudo nsenter --net=/var/run/netns/netns0 bash -c "ip route add default via 172.18.0.1"
# netns1 (same command)

Now containers can reach external addresses (e.g., 8.8.8.8) after applying NAT:

$ sudo iptables -t nat -A POSTROUTING -s 172.18.0.0/16 ! -o br0 -j MASQUERADE

Ping tests confirm internet connectivity.

Port publishing (exposing container services)

To 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, add DNAT rules:

# traffic arriving on the host’s eth0
sudo iptables -t nat -A PREROUTING -d 10.0.2.15 -p tcp --dport 5000 -j DNAT --to-destination 172.18.0.10:5000
# local traffic generated on the host
sudo iptables -t nat -A OUTPUT -d 10.0.2.15 -p tcp --dport 5000 -j DNAT --to-destination 172.18.0.10:5000

Enable bridge netfilter so iptables can see bridged traffic:

sudo modprobe br_netfilter

After these rules, curl 10.0.2.15:5000 returns the container’s HTTP response.

Understanding Docker network drivers

Docker’s --network host mode shares the host’s network namespace, while --network none leaves only a loopback interface. The default --network bridge mode mirrors the bridge setup described above, allowing containers to communicate via a virtual switch.

Rootless containers and networking

Rootless containers (e.g., with Podman) cannot create veth pairs directly because that requires root privileges. They rely on slirp4netns, which provides user‑space networking via a TAP device. However, rootless containers lack raw socket capabilities, so tools like ping do not work inside them.

Conclusion

The presented approach—using network namespaces, veth pairs, Linux bridges, routing, and NAT—is one of the most common ways to build isolated container networks on a single host. Many other solutions exist, often provided by third‑party plugins, but they all depend on the same underlying Linux network virtualization primitives.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

network isolationbridgeiptablescontainer networkingLinux NamespacesVeth
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.