{"record":{"id":"de0f83527785ddc9","repo":"slackhq/nebula","slug":"created-dev-net-tun-but-still-failed-w","errorCode":null,"errorMessage":"created /dev/net/tun, but still failed: %w","messagePattern":"created /dev/net/tun, but still failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"overlay/tun_linux.go","lineNumber":101,"sourceCode":"// openTunDev opens /dev/net/tun, creating the device node first if it's\n// missing (docker containers occasionally omit it).\nfunc openTunDev() (int, error) {\n\tfd, err := unix.Open(\"/dev/net/tun\", os.O_RDWR, 0)\n\tif err == nil {\n\t\treturn fd, nil\n\t}\n\tif !os.IsNotExist(err) {\n\t\treturn -1, err\n\t}\n\tif err = os.MkdirAll(\"/dev/net\", 0755); err != nil {\n\t\treturn -1, fmt.Errorf(\"/dev/net/tun doesn't exist, failed to mkdir -p /dev/net: %w\", err)\n\t}\n\tif err = unix.Mknod(\"/dev/net/tun\", unix.S_IFCHR|0600, int(unix.Mkdev(10, 200))); err != nil {\n\t\treturn -1, fmt.Errorf(\"failed to create /dev/net/tun: %w\", err)\n\t}\n\tfd, err = unix.Open(\"/dev/net/tun\", os.O_RDWR, 0)\n\tif err != nil {\n\t\treturn -1, fmt.Errorf(\"created /dev/net/tun, but still failed: %w\", err)\n\t}\n\treturn fd, nil\n}\n\n// tunSetIff runs TUNSETIFF with the given flags and returns the kernel-chosen device name on success.\nfunc tunSetIff(fd int, name string, flags uint16) (string, error) {\n\tvar req ifReq\n\treq.Flags = flags\n\tcopy(req.Name[:], name)\n\tif err := ioctl(uintptr(fd), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&req))); err != nil {\n\t\treturn \"\", err\n\t}\n\treturn strings.Trim(string(req.Name[:]), \"\\x00\"), nil\n}\n\n// tsoOffloadFlags are the TUN_F_* bits we ask the kernel to enable when a TSO-capable TUN is available.\nconst tsoOffloadFlags = unix.TUN_F_CSUM | unix.TUN_F_TSO4 | unix.TUN_F_TSO6 | unix.TUN_F_TSO_ECN\n","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/tun_linux.go#L83-L119","documentation":"openTunDev (overlay/tun_linux.go:101), after successfully creating /dev/net/tun via mknod, opens it read-write. This error wraps an open failure that occurs despite the node existing, meaning the TUN device is unusable even after provisioning.","triggerScenarios":"unix.Open(\"/dev/net/tun\", O_RDWR, 0) fails after mknod succeeded: the kernel lacks tun support (tun module not loaded/built in), EACCES on device permissions, or ENODEV/ENXIO when the kernel has no TUN driver.","commonSituations":"Minimal kernels or VPS hosts without the tun kernel module (modprobe tun fails); hardened containers granting mknod but denying device access; stale/mismatched device node permissions (0600 owned by another user).","solutions":["Load the kernel module: modprobe tun (and ensure it loads at boot).","Verify kernel support: CONFIG_TUN=y/m; check 'ls /sys/class/misc/tun'.","Fix permissions/ownership on /dev/net/tun so the running user can open it O_RDWR.","Grant the container access to the device (--device /dev/net/tun) and CAP_NET_ADMIN for the subsequent TUNSETIFF ioctl."],"exampleFix":"// before (module missing)\n$ ls /dev/net/tun   # node created but open fails\n// after\n$ modprobe tun\n$ docker run --device /dev/net/tun --cap-add NET_ADMIN nebula-image","handlingStrategy":"validation","validationCode":"if _, err := os.Stat(\"/sys/class/misc/tun\"); os.IsNotExist(err) {\n\treturn errors.New(\"kernel lacks TUN support; load the tun module (modprobe tun)\")\n}\nif err := unix.Access(\"/dev/net/tun\", unix.W_OK); err != nil {\n\treturn fmt.Errorf(\"no write access to /dev/net/tun: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"fd, err := openTunDev()\nif err != nil && strings.Contains(err.Error(), \"created /dev/net/tun, but still failed\") {\n\t// kernel/module or permission issue; prompt operator to modprobe tun or fix perms\n}","preventionTips":["Ensure CONFIG_TUN is enabled and the tun module loads at boot on hosts.","Verify /dev/net/tun permissions allow O_RDWR for the running user.","In containers, mount the real device so kernel-backed access is guaranteed.","Smoke-test 'tun' availability in host/instance provisioning before deploying nebula."],"tags":["linux","tun","kernel","permissions"],"backgroundTag":"tun-device-open-failed","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}