slackhq/nebula · error

a device name in the format of /dev/tunN must be specified

Error message

a device name in the format of /dev/tunN must be specified

What it means

newTun on OpenBSD requires an explicit tun device name via the 'tun.dev' config key. If the value is empty, the constructor refuses to proceed because OpenBSD tun devices must be opened by path (/dev/tunN), unlike Linux which can clone /dev/net/tun. This error signals the mandatory config key is missing.

Source

Thrown at overlay/tun_openbsd.go:73

	Routes      atomic.Pointer[[]Route]
	routeTree   atomic.Pointer[bart.Table[routing.Gateways]]
	l           *slog.Logger
	f           *os.File
	fd          int
}

var deviceNameRE = regexp.MustCompile(`^tun[0-9]+$`)

func newTunFromFd(_ *config.C, _ *slog.Logger, _ int, _ []netip.Prefix) (*tun, error) {
	return nil, fmt.Errorf("newTunFromFd not supported in openbsd")
}

func newTun(c *config.C, l *slog.Logger, vpnNetworks []netip.Prefix, _ bool) (*tun, error) {
	// Try to open tun device
	var err error
	deviceName := c.GetString("tun.dev", "")
	if deviceName == "" {
		return nil, fmt.Errorf("a device name in the format of /dev/tunN must be specified")
	}
	if !deviceNameRE.MatchString(deviceName) {
		return nil, fmt.Errorf("a device name in the format of /dev/tunN must be specified")
	}

	fd, err := unix.Open("/dev/"+deviceName, os.O_RDWR, 0)
	if err != nil {
		return nil, err
	}

	err = unix.SetNonblock(fd, true)
	if err != nil {
		l.Warn("Failed to set the tun device as nonblocking", "error", err)
	}

	t := &tun{
		f:           os.NewFile(uintptr(fd), ""),
		fd:          fd,

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Set 'tun.dev: /dev/tun0' (or the appropriate /dev/tunN) in the config file
  2. Verify with `ls /dev/tun*` which tun devices exist and pick a free one
  3. Create the device if missing: `cd /dev && sh MAKEDEV tun0`

Example fix

# before
tun:
  enabled: true
# after
tun:
  enabled: true
  dev: /dev/tun0
Defensive patterns

Strategy: validation

Validate before calling

dev := cfg.GetString("tun.dev", "")
if dev == "" {
    return fmt.Errorf("tun.dev must be set on OpenBSD, e.g. /dev/tun0")
}
if _, err := os.Stat("/dev/" + strings.TrimPrefix(dev, "/dev/")); err != nil {
    return fmt.Errorf("tun device %s not found", dev)
}

Prevention

When it happens

Trigger: Starting nebula with tun.enabled and no 'tun.dev' set in the config file (c.GetString("tun.dev", "") returns "").

Common situations: Copying a Linux-oriented config to an OpenBSD host; forgetting platform-specific tun settings; generating configs from templates that omit tun.dev.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/70e76c243d40b754. Report an issue: GitHub.