The container would not open its tunnel, so the privileged flag went in, and now it works. What that sequence established is that at least one permission was missing, and it says nothing about which one. Privileged mode grants a set of capabilities and device access far wider than a tunnel interface needs.

What the Flag Actually Changes

A privileged container receives broad capabilities and access to host devices, which is a much larger grant than the networking path requires. The exact set is documented by the runtime rather than fixed by folklore, and the Docker container run documentation describes the privilege options available. Reading it once is enough to see that tunnelling is a small part of the total.

Two narrower requirements cover most VPN containers. Configuring an interface needs the network administration capability, and opening the tunnel device needs access to that specific device node. Those are separate grants, and supplying both is still narrower than the blanket option. The rest of the privileged set has nothing to do with the tunnel. It exists for workloads that genuinely need host-level access, and a VPN container is usually not one of them.

Match Each Error to One Prerequisite

The error message tells you which prerequisite is missing if you read it before suppressing it. A message about a device node names the device, a message about an operation not permitted names a capability, and a message about a module or a sysctl names kernel support. Each of those has a different fix, and only one of them is a capability.

A missing configuration file stays missing after every capability is granted, which is why privileged mode sometimes changes nothing at all. The container starts, the tunnel still fails, and the real error was never about permissions. Kernel support is the third case and the most easily misread. A module that is not loaded on the host cannot be loaded from inside an unprivileged container, and granting more capabilities inside the container does not change the host's state.

Check the Requirement, Not the Symptom

Start from the minimal invocation the image documents, run it, and keep the exact failure text. Then add one grant at a time and note which addition changed the result.

ls -l /dev/net/tun
docker run --rm --cap-add NET_ADMIN --device /dev/net/tun image:tag
ip -br link show type tun

A container that can see the device and hold the capability but still fails is telling you the problem is elsewhere. That is a useful result, and privileged mode would have hidden it.

Check the device permissions on the host as well, because a correctly granted device node with the wrong group ownership produces the same error as a missing grant.

Record the Narrowest Grant That Works

Write down each device and capability the deployment needs, with the error that justified it. That record is what lets the next person remove something safely, and it is what an auditor will ask for when a container is reported as privileged.

Review the surrounding context too, because host networking, host mounts and runtime options can each widen the impact of a permission grant. An isolated lab invocation that combines all of them is not a production configuration, however well it worked. Test the application, its DNS behaviour and a tunnel failure before you call the deployment finished. Permission to create an interface is not an egress policy, and a container that can tunnel perfectly still routes whatever the application sends.

Ebitabo ebifaananyi