A network namespace is a completely separate copy of the Linux network stack: its own interfaces, IP addresses, routing table, firewall rules and port numbers. Docker gives every container one. You can create them by hand with ip netns, to test network setups, isolate an application’s traffic, or understand what container networking does under the hood.
Overview of all namespace types: Linux namespaces.
Create a namespace
sudo ip netns add lab
ip netns list
sudo ip netns exec lab ip addr # only a loopback interface, and it's down
sudo ip netns exec lab ip link set lo up
Anything run with ip netns exec lab … sees only the namespace’s network.
Connect it to the host with a veth pair
A veth pair is a virtual cable: two interfaces, where packets entering one exit the other.
sudo ip link add veth-host type veth peer name veth-lab
sudo ip link set veth-lab netns lab
sudo ip addr add 10.200.0.1/24 dev veth-host
sudo ip link set veth-host up
sudo ip netns exec lab ip addr add 10.200.0.2/24 dev veth-lab
sudo ip netns exec lab ip link set veth-lab up
sudo ip netns exec lab ip route add default via 10.200.0.1
ping -c2 10.200.0.2 # host → namespace
sudo ip netns exec lab ping -c2 10.200.0.1 # namespace → host
See ip command.
Give it internet access (NAT)
sudo sysctl -w net.ipv4.ip_forward=1
sudo nft add table ip natlab
sudo nft 'add chain ip natlab post { type nat hook postrouting priority 100; }'
sudo nft add rule ip natlab post ip saddr 10.200.0.0/24 oifname "eth0" masquerade
sudo ip netns exec lab ping -c2 1.1.1.1
Replace eth0 with your public interface (ip route | grep default). DNS inside the namespace uses /etc/netns/lab/resolv.conf if it exists, or the host’s /etc/resolv.conf. If your firewall’s forward policy is drop (UFW, Docker), also allow forwarding for veth-host. See nftables.
Run an application inside
sudo ip netns exec lab sudo -u alice python3 -m http.server 8000
curl http://10.200.0.2:8000/ # from the host
The app binds port 8000 inside the namespace. It doesn’t conflict with anything listening on the host.
Practical uses
- Test network configurations (firewall rules, routing, MTU) without touching the host’s real network.
- Per-application VPN routing: move a WireGuard interface into a namespace, so only apps started there use the VPN (a common “split tunnel” technique). See WireGuard VPN server.
- Simulate multi-host networks on one VPS for learning (routers, bridges, multiple namespaces).
- Debug containers with host tools, by entering their namespace:
nsenter -t <pid> -n ss -tlnp.
How Docker does it
For each container on the default bridge network, Docker:
- creates a network namespace;
- creates a veth pair, putting one end in the container (
eth0) and attaching the other to thedocker0bridge; - assigns an IP from the bridge subnet, and sets the default route;
- adds NAT (masquerade) and port-forwarding (DNAT) rules for published ports.
That’s the same set of steps you just did by hand. Docker’s namespaces aren’t listed by ip netns, but you can reach them via the container’s PID. See Docker container IP address.
Clean up
sudo ip netns del lab # also removes veth-lab (and its peer)
sudo nft delete table ip natlab
Namespaces created with ip netns add don’t survive a reboot.
Quick reference
| Task | Command |
|---|---|
| Create / list / delete | ip netns add X / ip netns list / ip netns del X |
| Run inside | ip netns exec X <cmd> |
| veth pair | ip link add a type veth peer name b |
| Move into namespace | ip link set b netns X |
| Internet via NAT | ip_forward=1 + masquerade rule |
Related: Linux cgroups and Linux network bonding.