fatedier/frp · error
failed to create TUN device '%s': %w
Error message
failed to create TUN device '%s': %w
What it means
Linux implementation of vnet's openTun: wireguard/tun's CreateTUN failed to create the utun device, and this wraps the driver-level error. Creating a TUN device requires the kernel TUN/TAP module and privileges (CAP_NET_ADMIN), so on Linux this almost always means /dev/net/tun is missing/inaccessible or the process lacks permission.
Source
Thrown at pkg/vnet/tun_linux.go:43
"github.com/vishvananda/netlink"
"golang.zx2c4.com/wireguard/tun"
)
const (
baseTunName = "utun"
defaultMTU = 1420
)
func openTun(_ context.Context, addr string) (tun.Device, error) {
name, err := findNextTunName(baseTunName)
if err != nil {
name = getFallbackTunName(baseTunName, addr)
}
tunDevice, err := tun.CreateTUN(name, defaultMTU)
if err != nil {
return nil, fmt.Errorf("failed to create TUN device '%s': %w", name, err)
}
actualName, err := tunDevice.Name()
if err != nil {
return nil, err
}
ifn, err := net.InterfaceByName(actualName)
if err != nil {
return nil, err
}
link, err := netlink.LinkByName(actualName)
if err != nil {
return nil, err
}
ip, cidr, err := net.ParseCIDR(addr)View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Load the module on the host: `sudo modprobe tun` and ensure /dev/net/tun exists (mknod /dev/net/tun c 10 200)
- Run frpc with CAP_NET_ADMIN (root, or setcap/ambients); in Docker add --cap-add=NET_ADMIN --device /dev/net/tun (or --privileged)
- If the kernel truly lacks TUN support, disable vnet: set vnet.enabled = false in frpc.toml
- Check dmesg/audit for SELinux/AppArmor denials when the device node exists yet creation fails
Example fix
# before docker run myfrpc # vnet enabled -> failed to create TUN device 'utun0': operation not permitted # after docker run --cap-add=NET_ADMIN --device /dev/net/tun myfrpc
Defensive patterns
Strategy: validation
Validate before calling
// capability check before enabling vnet on linux
func tunAvailable() bool {
f, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
if err != nil { return false }
f.Close()
return os.Geteuid() == 0 || hasCapNetAdmin() // hasCapNetAdmin: parse /proc/self/status CapEff
} Try / catch
if err := startVnet(); err != nil {
if strings.Contains(err.Error(), "failed to create TUN device") {
log.Printf("vnet needs /dev/net/tun + CAP_NET_ADMIN; disabling vnet: %v", err)
cfg.Vnet.Enabled = false // degrade gracefully
}
} Prevention
- In containers: --cap-add=NET_ADMIN --device /dev/net/tun
- Pre-check /dev/net/tun existence at startup and fail with a clear message
- Run frpc as root or grant CAP_NET_ADMIN via setcap/systemd
When it happens
Trigger: frpc started with vnet.enabled = true in an environment where: /dev/net/tun does not exist (module not loaded / not passed into container), the process runs as non-root without CAP_NET_ADMIN, the container lacks --device /dev/net/tun / --privileged, or the tun kernel module is blacklisted.
Common situations: Running frpc in Docker/Kubernetes without privileged mode or without mounting /dev/net/tun; minimal VMs/WSL2 where the tun module is absent; systemd hardening (RestrictAddressFamilies, CapabilityBoundingSet) dropping AF_UNIX/CAP_NET_ADMIN; already-exhausted or locked-down device creation.
Related errors
- add route to %v error: %v
- virtual net is not supported on this platform (%s/%s)
- failed to load existing data: %w
- failed to create directory: %w
- failed to create temp file: %w
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/c4f71f41b2e4fc2f.
Report an issue: GitHub.