This episode compares the two container modes: privileged, which is fast but risky because root inside it equals root on the host, and unprivileged, which uses user namespaces and idmapping (subuid/subgid) so it's safe for multi-tenant environments.

In episode 4 your first container c1 is running. But the question is: is that container running as privileged or unprivileged? The difference between these two modes is the most fundamental security decision in LXC. In episode 5 we break down both: why privileged is dangerous, how unprivileged uses user namespaces and idmapping, and when each is worth using.
A privileged container runs directly as root on the host without user mapping. That means UID 0 inside the container is UID 0 on the host, with all the capabilities that entails. LXC tries to reduce the risk with AppArmor and seccomp defaults (episode 13), but the isolation boundary remains thin.
Its strengths are speed and simplicity: no idmapping layer, direct access to devices (e.g. /dev/loop*, kernel modules) works out of the box, and I/O performance is closest to the host. That's why privileged is still used for workloads that need raw hardware access.
Warning
The golden rule: never grant privileged container access to parties you don't fully trust. Privileged containers suit infrastructure you manage yourself within a single trust domain — not public tenants.
An unprivileged container is LXC's modern default. It uses user namespaces to map UIDs/GIDs inside the container to harmless UIDs/GIDs on the host. Root inside the container (UID 0) is mapped to a regular user on the host — e.g. UID 100000 — so actions considered "as root" inside the container still run with a regular user's privileges from the host's point of view.
We'll look at the mapping in detail in episode 15, but here's the gist:
grep "$USER" /etc/subuid
grep "$USER" /etc/subgidA typical output: devnull:100000:65536 — meaning UID 0-65535 inside the container maps to UID 100000-165535 on the host. Each container can get a different range.
Unprivileged has a small cost: access to some host devices is restricted, and certain cases (bind-mounts with unusual permissions, or direct hardware access) need extra configuration. Pure performance is nearly the same — user namespaces add no meaningful runtime overhead once the container is running.
Look at the c1 container config from episode 4:
cat /var/lib/lxc/c1/configNotice the lines that determine the mode:
lxc.include = /usr/share/lxc/config/common.conf.d/00-lxcfs.conf
lxc.include = /usr/share/lxc/config/ubuntu.common.conf
lxc.include = /usr/share/lxc/config/ubuntu.userns.conf
lxc.rootfs.path = dir:/var/lib/lxc/c1/rootfsThe presence of the ubuntu.userns.conf include indicates the container is running unprivileged. Conversely, without a userns include (and without lxc.idmap), the container runs privileged. You can also see it at runtime: files created by root inside the container will appear owned by a large UID (e.g. 100000) when viewed from the host.
Tip
Quick check: from the host, run ls -n /var/lib/lxc/c1/rootfs/. If file owners appear as large numbers like 100000, the container is unprivileged. If 0, it's privileged.
For the rest of this series, we assume unprivileged unless stated otherwise, and we use the existing c1 container as our practice base.
Key takeaways:
/etc/subuid and /etc/subgid determine the per-user mapping ranges.In the next episode 6 we'll cover networking: bridge, veth & NAT — how lxcbr0 becomes the default NAT bridge, how veth pairs work, configuration in /etc/lxc/default.conf and /etc/lxc/lxc-usernet, and the network modes none, veth, macvlan, and phys along with static IP/DHCP.