NixOS

A services.ncclient module runs ncclient declaratively as a systemd service — an alternative to the Docker image, the Windows service, or a hand-written unit (see ncclient CLI: Run as a service). It’s exposed by the same flake.nix as the server module, as nixosModules.client.

{
  inputs.nebula-commander.url = "github:NixRTR/nebula-commander";

  outputs = { self, nixpkgs, nebula-commander, ... }: {
    nixosConfigurations.yourHost = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        ./configuration.nix
        nebula-commander.nixosModules.client
      ];
    };
  };
}

Or import nix/client-module.nix directly by path if you’re not using a flake, the same way the server module can be.

services.ncclient = {
  enable = true;
  server = "https://nebula.example.com";
  # One-time enrollment: a file holding the enrollment code, consumed once (the
  # unit only runs `ncclient enroll` when no token exists yet at stateDir/token).
  enrollCodeFile = "/run/secrets/ncclient-enroll-code";
  acceptDns = true;
};

Then rebuild: nixos-rebuild switch (path-based) or nixos-rebuild switch --flake .#yourHost. See NixOS usage for controlling the service, running ncclient commands, and re-enrolling.

OptionTypeDefaultDescription
enablebool—Enable the ncclient service
packagepackagebuilt from nix/client-package.nixThe ncclient package
nebulaPackagepackagepkgs.nebulaPackage providing the nebula/nebula-cert binaries ncclient orchestrates
serverstring— (required)Nebula Commander server URL
enrollCodeFilenull or pathnullPath to a file containing a one-time enrollment code. When set and no token exists yet, a oneshot unit runs ncclient enroll before the main service starts. Leave null if you provision the token file out of band.
intervalint60Poll interval in seconds
outputDirstring/var/lib/ncclient/nebulaDirectory ncclient writes Nebula’s config/certs/binary to
acceptDnsboolfalseAccept and apply DNS settings pushed by Nebula Commander
adminGroupsnull or list of strings[ "wheel" "sudo" ]Active local users in these groups may change the device (desktop app enrollment, settings, routes, exit node; start/stop/restart ncclient.service) without a password. Everyone else needs an administrator’s password. null lets any active local user do it (single-user machines only).
stateDirstring/var/lib/ncclientDirectory holding the device token and settings.json together on the same persistent path — both must live in the same place or the node’s identity is lost on restart even though the token survives

The service runs as root, matching the Windows Service (LocalSystem) and Docker image (root-in-container) precedent above — Nebula needs to create a TUN device. --nebula/--restart-service are intentionally not exposed; nebula is resolved via PATH (from nebulaPackage), matching the Docker image’s approach.

Desktop app

On a NixOS desktop, you can add the Linux desktop app alongside the service with the nixosModules.client-desktop module (or nix/client-desktop-module.nix by path):

modules = [
  ./configuration.nix
  nebula-commander.nixosModules.client
  nebula-commander.nixosModules.client-desktop
];
services.ncclient.enable = true;          # the service the app controls
services.ncclient-desktop.enable = true;  # adds "Nebula Commander" to the app launcher
OptionTypeDefaultDescription
enablebool—Install the Nebula Commander desktop app (GTK4/libadwaita)
packagepackagebuilt from nix/client-desktop-package.nixThe desktop app package

The desktop module installs the app and turns on security.polkit.enable (as a default you can override), since every request the app makes is authorized by polkit. services.ncclient registers the D-Bus policy and polkit rules the app needs. Any user in an active local session can view status; members of adminGroups (default wheel/sudo) can enroll, change settings, accept routes, and start/stop/restart ncclient.service without a password prompt, and everyone else needs an administrator’s password.