1

I'm trying to run nebula (an overlay networking tool) as a systemd user service, NOT as a system service with user and group defined in the unit file. All examples about running a service with CAP_NET_ADMIN as a non-root user I have found, do it as a system service with specific user and group defined in the unit file (example 1, non-nebula CAP_NET_ADMIN example 2). I have not tried doing it that way but I have no doubt that it would work as there are numerous articles and guides about setting it up that way.

I'm running Debian 13 with systemd 257 (257.7-1) and nebula 1.9.3.

I've created the unit file based on the example 1.

$ cat ~/.config/systemd/user/nebula.service 
[Unit]
Description=nebula

[Service]
WorkingDirectory=~
AmbientCapabilities=CAP_NET_ADMIN
Type=exec
LimitNOFILE=65535
ExecStart=nebula -config .config/nebula/config.yml
KillSignal=SIGINT
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=default.target

Below is the result after running systemctl --user daemon-reload && systemctl --user start nebula and journalctl --user -u nebula

Starting nebula.service - nebula...
nebula.service: Failed to apply ambient capabilities (before UID change): Operation not permitted
nebula.service: Failed at step CAPABILITIES spawning nebula: Operation not permitted
nebula.service: Main process exited, code=exited, status=218/CAPABILITIES
nebula.service: Failed with result 'exit-code'.
Failed to start nebula.service - nebula.

systemd.exec manual has the following disclaimer for AmbientCapabilities option, which is required to set the CAP_NET_ADMIN to allow the service to create tun/tap interface:

These options are only available for system services, or for services running in per-user instances of the service manager in which case PrivateUsers= is implicitly enabled (requires unprivileged user namespaces support to be enabled in the kernel via the "kernel.unprivileged_userns_clone=" sysctl).

If I understand it correctly, my use case falls under the "services running in per-user instances of the service manager" and unprivileged user namespaces support is enabled in my system (I didn't touch this option, it appears to be default configuration in Debian 13):

$ /sbin/sysctl kernel.unprivileged_userns_clone
kernel.unprivileged_userns_clone = 1

I don't know anything about user namespaces, but since the manual mentions the PrivateUsers option I tried to play around with all possible values in the unit file.


PrivateUsers=self (same result when it is set to true)

Starting nebula.service - nebula...
Started nebula.service - nebula.
time="2025-09-04T21:45:39+03:00" level=info msg="Firewall rule added" firewallRule="map[caName: caSha: direction:outgoing endPort:0 groups:[] host:any ip: localIp: proto:0 startPort:0]"
time="2025-09-04T21:45:39+03:00" level=info msg="Firewall rule added" firewallRule="map[caName: caSha: direction:incoming endPort:0 groups:[] host:any ip: localIp: proto:1 startPort:0]"
time="2025-09-04T21:45:39+03:00" level=info msg="Firewall started" firewallHashes="*XXX*,FNV:*XXX*"
time="2025-09-04T21:45:39+03:00" level=error msg="Failed to get a tun/tap device" error="operation not permitted"
nebula.service: Main process exited, code=exited, status=1/FAILURE
nebula.service: Failed with result 'exit-code'.

PrivateUsers=identity

Starting nebula.service - nebula...
nebula.service: Failed to set up user namespacing for unprivileged user: Operation not permitted
nebula.service: Failed at step USER spawning nebula: Operation not permitted
nebula.service: Main process exited, code=exited, status=217/USER
nebula.service: Failed with result 'exit-code'.
Failed to start nebula.service - nebula.

Then I tried to run capsh instead of nebula as it appears to show what capabilities the process is actually getting using the following settings in the same unit file:

PrivateUsers=self
ExecStart=/sbin/capsh --print

journalctl log for this run:

Starting nebula.service - nebula...
Started nebula.service - nebula.
Current: cap_net_admin=eip
Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read,cap_perfmon,cap_bpf,cap_checkpoint_restore
Ambient set =cap_net_admin
Current IAB: ^cap_net_admin
Securebits: 00/0x0/1'b0 (no-new-privs=0)
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
 secure-no-ambient-raise: no (unlocked)
uid=60198(XXX) euid=60198(XXX)
gid=60198(XXX)
groups=60198(XXX)
Guessed mode: HYBRID (4)

It appears that when PrivateUsers=self it successfully sets the CAP_NET_ADMIN flag for the process, however, nebula is still unable to create the tun/tap device.

To rule out the possibility of nebula-specific issue, I also tried the following

PrivateUsers=self
ExecStart=strace ip tuntap add mode tap tap0

Still, operation not permitted.

Started nebula.service - nebula.
...
capget({version=_LINUX_CAPABILITY_VERSION_3, pid=0}, NULL) = 0
capget({version=_LINUX_CAPABILITY_VERSION_3, pid=0}, {effective=1<<CAP_NET_ADMIN, permitted=1<<CAP_NET_ADMIN, inheritable=1<<CAP_NET_ADMIN}) = 0
ioctl(1, TCGETS, 0x7ffe55fda310)        = -1 ENOTTY (Inappropriate ioctl for device)
socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE) = 3
setsockopt(3, SOL_SOCKET, SO_SNDBUF, [32768], 4) = 0
setsockopt(3, SOL_SOCKET, SO_RCVBUF, [1048576], 4) = 0
setsockopt(3, SOL_NETLINK, NETLINK_EXT_ACK, [1], 4) = 0
bind(3, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, 12) = 0
getsockname(3, {sa_family=AF_NETLINK, nl_pid=128596, nl_groups=00000000}, [12]) = 0
setsockopt(3, SOL_NETLINK, NETLINK_GET_STRICT_CHK, [1], 4) = 0
openat(AT_FDCWD, "/dev/net/tun", O_RDWR) = 4
ioctl(4, TUNSETIFF, 0x7ffe55fda330)     = -1 EPERM (Operation not permitted)
...
ioctl(TUNSETIFF): Operation not permitted
nebula.service: Main process exited, code=exited, status=1/FAILURE
nebula.service: Failed with result 'exit-code'.

Am I missing anything here? Is it supposed to work at all?

1 Answer 1

1

Obviously non-root users cannot just give themselves capabilities just by editing systemd user instance config file.

Running in a user namespace makes you effectively root in that namespace. But only for those syscalls which are covered by the user namespace (like file access).

You want to use network capabilities so you must run your process on both a user namespace and a network namespace. Add this:

PrivateNetwork=true
4
  • Thank you for clarification and the advise. Nebula is able to create the tun interface now, but as I understand, when using PrivateNetwork=true it isolates the process from the host namespace completely (at least in the networking part), so it no longer sees host network interfaces and thus unable to communicate with the outside world. Commented Sep 5 at 13:03
  • Here it is unable to reach DNS. Changing the endpoint to IP results in similar "network is unreachable" message. "Nebula interface is active" boringcrypto=false build=1.9.3 interface=nebula1 network=192.168.111.100/24 udpAddr="0.0.0.0:37231" "Failed to set tun tx queue length" error="operation not permitted" "DNS resolution failed for static_map host" error="lookup google.com on 1.0.0.1:53: dial udp 1.0.0.1:53: connect: network is unreachable" hostname=google.com network=ip4 Is there any way to make it see the Internet? Commented Sep 5 at 13:12
  • @user31422095 Sure, you must connect the unit namespace with the main namespace. This is done with veth pairs. You can either add the outer veth to a bridge or use the outer namespace as a (masquerading) router. How that is done best / easiest depends on your network situation. unix.stackexchange.com/questions/537014/… unix.stackexchange.com/questions/491366/… Commented Sep 5 at 14:30
  • Thank you, I will review and follow up. Commented Sep 5 at 15:20

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.