Skip to content
LinuxHow-To July 11, 2026 4 min readViews unavailable

Building an Isolated Network Namespace for Testing

Creating a separate network stack on the same Linux machine to test firewall rules, routing configurations, or networked software without touching the host's real network configuration.

A network namespace gives a process (or group of processes) its own completely separate network stack — its own interfaces, routing table, firewall rules, and even its own loopback address — isolated from the host’s real networking and from any other namespace. This is the same underlying mechanism containers use for network isolation, but it’s directly usable on its own with nothing more than iproute2, without needing a full container runtime, which makes it a genuinely convenient tool for testing networking configuration changes without any risk to the host’s actual connectivity.

Creating a namespace

ip netns add testns

This creates a new, empty network namespace named testns. At this point it has no interfaces at all — not even loopback active — and is completely isolated from the host’s networking.

Bringing up loopback inside it

ip netns exec testns ip link set lo up

ip netns exec <name> <command> runs any command inside the specified namespace’s network context — here, bringing up the loopback interface, which most networked software inside the namespace will expect to exist and be up.

Connecting the namespace to the host with a veth pair

An isolated namespace with no connectivity at all is useful for some tests, but usually you want it reachable from the host (or the wider network) for realistic testing. A veth (virtual ethernet) pair is a connected pair of virtual interfaces, functioning like a cable with one end in the host’s default namespace and the other end moved into the new namespace:

ip link add veth-host type veth peer name veth-ns
ip link set veth-ns netns testns

Now veth-host remains in the host’s default namespace, and veth-ns exists inside testns, with the two acting as if directly cabled together.

ip addr add 10.200.1.1/24 dev veth-host
ip link set veth-host up

ip netns exec testns ip addr add 10.200.1.2/24 dev veth-ns
ip netns exec testns ip link set veth-ns up

At this point, the host can reach 10.200.1.2 and the namespace can reach 10.200.1.1 — a private, point-to-point link between the host’s default namespace and the isolated testns, verifiable directly:

ping -c 3 10.200.1.2

Testing firewall rules in isolation

This is one of the most practical uses of a network namespace: testing a new nftables/iptables ruleset against real traffic patterns without any risk of locking yourself out of the host’s actual network, or disrupting other services running on it. Rules applied inside testns via ip netns exec testns nft ... affect only that namespace’s traffic, entirely independent of whatever ruleset is active on the host:

ip netns exec testns nft add table inet filter
ip netns exec testns nft add chain inet filter input { type filter hook input priority 0 \; }
ip netns exec testns nft add rule inet filter input drop

Testing that this rule actually drops traffic (via a ping from the host to 10.200.1.2 now failing) confirms the ruleset’s behavior in complete isolation from the host’s own firewall, before ever considering applying anything similar to a real, in-use network namespace.

Running an actual networked process inside the namespace

Any process can be launched directly inside a namespace, not just single commands:

ip netns exec testns python3 -m http.server 8080

This starts a simple HTTP server bound only within testns’s network stack — reachable from the host at 10.200.1.2:8080 (over the veth link), but not exposed anywhere else, which is a convenient, disposable way to stand up a test service for exercising client configuration or firewall rules against, without any of it touching the host’s actual listening ports or interfaces.

Cleaning up

ip netns delete testns

Deleting the namespace removes it and everything inside it — the veth pair’s namespace-side end goes with it (the host-side end, veth-host, needs a separate ip link delete veth-host if it wasn’t automatically cleaned up), leaving the host’s real network configuration exactly as it was before, since none of this ever touched it in the first place.

Why this beats testing directly against the host’s live configuration

The core value here is that every step above is fully reversible and fully isolated — a firewall rule that would otherwise be nerve-wracking to test on a machine’s actual live ruleset (with real risk of a dropped SSH session locking you out) can be tested inside a throwaway namespace with zero risk to the host’s actual reachability, and torn down completely with a single command once you’re satisfied it behaves correctly.