2026-05-29
For two decades I've watched people reach for Docker to test whether a script does the right thing with mount points or network failures. Docker is a daemon-and-bridge cathedral. unshare is a one-line wrapper around clone(2) namespace flags — and it has shipped in util-linux since 2008. It's the bare metal underneath every container runtime. Linux namespaces, exposed directly.
You want a command run in isolation: a fresh PID space, a private mount table, a clean network stack, or a fake-root identity — without overlayfs, image registries, or daemons. Containers are the production answer; unshare is the debugging answer.
# Run htop so it only sees its own process tree
unshare --pid --fork --mount-proc htop
# Mount a tmpfs nobody else can see
sudo unshare --mount --propagation=private sh -c '
mount -t tmpfs none /mnt
echo private to this shell > /mnt/note
ls /mnt
'
# (back in the host shell, /mnt is untouched)
# A network namespace with nothing in it — perfect for
# testing offline behaviour or DNS failure modes
sudo unshare --net sh -c '
ip link # only loopback, and it is DOWN
curl example.com # connection refused, predictably
'
# Become root without being root
unshare --user --map-root-user sh -c '
id # uid=0(root) gid=0(root)
chown 0:0 /tmp/scratch # works — inside the namespace
'
# Everything at once: your own pocket container, no Docker
sudo unshare --pid --mount --net --uts --ipc --user \
--fork --mount-proc --map-root-user bash
chroot isolates only the filesystem. A chrooted process still sees the host's /proc, can signal host PIDs, and can talk to host sockets.docker run needs a daemon, an image, and a bridge. Best case it cold-starts in ~700ms. unshare starts in single-digit milliseconds.bwrap, firejail, systemd-run --user are wonderful but configuration-heavy. unshare is one flag per namespace and exits when the child does.--fork is mandatory with --pid. The unshare process itself stays in the old PID namespace; only its child enters the new one. Forget --fork and the next hour will confuse you.--mount-proc re-mounts /proc inside the new PID namespace. Without it, ps reads the host's /proc and lies to you.--user --map-root-user gives you UID 0 inside the namespace; files on the host still belong to your real UID. This is exactly how rootless Podman works.nsenter: grab the child's PID and run nsenter --target $PID --all bash to drop a second shell into the same namespaces.--keep-caps preserves file capabilities across the transition — handy when running setuid-shaped binaries under --user.--propagation=private stops your test mounts from leaking back to the host via shared subtrees. Default propagation on most distros is shared; that has burned many scripts.Reproducing a "works in the container!" bug without rebuilding the container. Testing what your installer does to /etc/fstab without risking your laptop. Watching a network-naive program fail predictably. Building chroots and verifying their integrity. Teaching how containers actually work — there's no magic, only clone(2) with flags.
The wizard's lesson: containers are not a thing. Namespaces are a thing. unshare shows you which thing.
unshare exposes Linux namespaces directly, giving you container-grade isolation in a single binary with no daemon, no images, and millisecond startup — perfect for testing mount, network, and PID behaviour the way the kernel sees it.
