**Kernel modules**: The container shares your host kernel, so OpenWrt’s kmod-* packages won’t work unless the host kernel already has those modules. Hardware-specific offloading, custom drivers, that sort of thing is out.
**Network interfaces**: You need to explicitly pass through physical interfaces (via macvlan, ipvlan, or phys device type in Incus). OpenWrt expects to own its WAN and LAN interfaces. It won’t just see the container’s default eth0 as a real NIC.
**Capabilities**: The container needs NET_ADMIN at minimum for nftables rules to work. In Incus this usually means `security.privileged=true` or adding the capability explicitly. Without it, OpenWrt’s firewall startup will fail silently.
**What works fine**: dnsmasq (DNS/DHCP), nftables filtering within the container’s network namespace, the luci web interface, most OpenWrt packages that don’t touch hardware directly.
**What doesn’t work well**: Hardware offloading, SQM/QoS that relies on kernel schedulers, anything needing SYS_MODULE capability, bridge VLAN filtering at the hardware level.
In my experience containers are great if you’re using OpenWrt mainly as a DNS/DHCP server or software firewall in a lab. For actual router duties with real traffic shaping on physical interfaces, the VM route is more predictable.
Yeah, iptables/nftables definitely work just fine in unprivileged containers.
They do net CAP_NET_ADMIN but they check for that capability against the network namespace and not against the entire kernel. Root in an unprivileged container absolutely has CAP_NET_ADMIN against its own network namespace.