1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 inherit (lib)
10 attrNames
11 getExe
12 literalExpression
13 maintainers
14 mapAttrs'
15 mkDefault
16 mkEnableOption
17 mkIf
18 mkMerge
19 mkOption
20 mkPackageOption
21 nameValuePair
22 optional
23 versionOlder
24 ;
25
26 inherit (lib.types)
27 attrsOf
28 port
29 str
30 submodule
31 ;
32
33 kernel = config.boot.kernelPackages;
34
35 cfg = config.services.netbird;
36in
37{
38 meta.maintainers = with maintainers; [
39 misuzu
40 thubrecht
41 ];
42 meta.doc = ./netbird.md;
43
44 options.services.netbird = {
45 enable = mkEnableOption "Netbird daemon";
46 package = mkPackageOption pkgs "netbird" { };
47
48 tunnels = mkOption {
49 type = attrsOf (
50 submodule (
51 { name, config, ... }:
52 {
53 options = {
54 port = mkOption {
55 type = port;
56 default = 51820;
57 description = ''
58 Port for the ${name} netbird interface.
59 '';
60 };
61
62 environment = mkOption {
63 type = attrsOf str;
64 defaultText = literalExpression ''
65 {
66 NB_CONFIG = "/var/lib/''${stateDir}/config.json";
67 NB_LOG_FILE = "console";
68 NB_WIREGUARD_PORT = builtins.toString port;
69 NB_INTERFACE_NAME = name;
70 NB_DAMEON_ADDR = "/var/run/''${stateDir}"
71 }
72 '';
73 description = ''
74 Environment for the netbird service, used to pass configuration options.
75 '';
76 };
77
78 stateDir = mkOption {
79 type = str;
80 default = "netbird-${name}";
81 description = ''
82 Directory storing the netbird configuration.
83 '';
84 };
85 };
86
87 config.environment = builtins.mapAttrs (_: mkDefault) {
88 NB_CONFIG = "/var/lib/${config.stateDir}/config.json";
89 NB_LOG_FILE = "console";
90 NB_WIREGUARD_PORT = builtins.toString config.port;
91 NB_INTERFACE_NAME = name;
92 NB_DAEMON_ADDR = "unix:///var/run/${config.stateDir}/sock";
93 };
94 }
95 )
96 );
97 default = { };
98 description = ''
99 Attribute set of Netbird tunnels, each one will spawn a daemon listening on ...
100 '';
101 };
102 };
103
104 config = mkMerge [
105 (mkIf cfg.enable {
106 # For backwards compatibility
107 services.netbird.tunnels.wt0.stateDir = "netbird";
108 })
109
110 (mkIf (cfg.tunnels != { }) {
111 boot.extraModulePackages = optional (versionOlder kernel.kernel.version "5.6") kernel.wireguard;
112
113 environment.systemPackages = [ cfg.package ];
114
115 networking.dhcpcd.denyInterfaces = attrNames cfg.tunnels;
116
117 systemd.network.networks = mkIf config.networking.useNetworkd (
118 mapAttrs'
119 (
120 name: _:
121 nameValuePair "50-netbird-${name}" {
122 matchConfig = {
123 Name = name;
124 };
125 linkConfig = {
126 Unmanaged = true;
127 ActivationPolicy = "manual";
128 };
129 }
130 )
131 cfg.tunnels
132 );
133
134 systemd.services =
135 mapAttrs'
136 (
137 name:
138 { environment, stateDir, ... }:
139 nameValuePair "netbird-${name}" {
140 description = "A WireGuard-based mesh network that connects your devices into a single private network";
141
142 documentation = [ "https://netbird.io/docs/" ];
143
144 after = [ "network.target" ];
145 wantedBy = [ "multi-user.target" ];
146
147 path = with pkgs; [ openresolv ];
148
149 inherit environment;
150
151 serviceConfig = {
152 ExecStart = "${getExe cfg.package} service run";
153 Restart = "always";
154 RuntimeDirectory = stateDir;
155 StateDirectory = stateDir;
156 StateDirectoryMode = "0700";
157 WorkingDirectory = "/var/lib/${stateDir}";
158 };
159
160 unitConfig = {
161 StartLimitInterval = 5;
162 StartLimitBurst = 10;
163 };
164
165 stopIfChanged = false;
166 }
167 )
168 cfg.tunnels;
169 })
170 ];
171}