1{
2 config,
3 pkgs,
4 lib,
5 ...
6}:
7with lib;
8let
9 cfg = config.services.veilid;
10 dataDir = "/var/db/veilid-server";
11
12 settingsFormat = pkgs.formats.yaml { };
13 configFile = settingsFormat.generate "veilid-server.conf" cfg.settings;
14in
15{
16 config = mkIf cfg.enable {
17 networking.firewall = mkIf cfg.openFirewall {
18 allowedTCPPorts = [ 5150 ];
19 allowedUDPPorts = [ 5150 ];
20 };
21
22 # Based on https://gitlab.com/veilid/veilid/-/blob/main/package/systemd/veilid-server.service?ref_type=heads
23 systemd.services.veilid = {
24 enable = true;
25 description = "Veilid Headless Node";
26 wants = [ "network-online.target" ];
27 before = [ "network-online.target" ];
28 wantedBy = [ "multi-user.target" ];
29 restartTriggers = [ configFile ];
30 environment = {
31 RUST_BACKTRACE = "1";
32 };
33 serviceConfig = {
34 ExecStart = "${pkgs.veilid}/bin/veilid-server -c ${configFile}";
35 ExecReload = "${pkgs.coreutils}/bin/kill -s HUP $MAINPID";
36 KillSignal = "SIGQUIT";
37 TimeoutStopSec = 5;
38 WorkingDirectory = "/";
39 User = "veilid";
40 Group = "veilid";
41 UMask = "0002";
42
43 CapabilityBoundingSet = "";
44 SystemCallFilter = [ "@system-service" ];
45 MemoryDenyWriteExecute = true;
46 NoNewPrivileges = true;
47 PrivateDevices = true;
48 PrivateTmp = true;
49 PrivateUsers = true;
50 ProtectHome = true;
51 ProtectClock = true;
52 ProtectControlGroups = true;
53 ProtectKernelLogs = true;
54 ProtectKernelModules = true;
55 ProtectKernelTunables = true;
56 ProtectProc = "invisible";
57 ProtectSystem = "strict";
58 ReadWritePaths = dataDir;
59
60 RestrictRealtime = true;
61 SystemCallArchitectures = "native";
62 LockPersonality = true;
63 RestrictSUIDSGID = true;
64 };
65 };
66 users.users.veilid = {
67 isSystemUser = true;
68 group = "veilid";
69 home = dataDir;
70 createHome = true;
71 };
72 users.groups.veilid = { };
73
74 environment = {
75 systemPackages = [ pkgs.veilid ];
76 };
77 services.veilid.settings = { };
78 };
79
80 options.services.veilid = {
81 enable = mkEnableOption "Veilid Headless Node";
82 openFirewall = mkOption {
83 default = false;
84 type = types.bool;
85 description = "Whether to open firewall on ports 5150/tcp, 5150/udp";
86 };
87 settings = mkOption {
88 description = ''
89 Build veilid-server.conf with nix expression.
90 Check <link xlink:href="https://veilid.gitlab.io/developer-book/admin/config.html#configuration-keys">Configuration Keys</link>.
91 '';
92 type = types.submodule {
93 freeformType = settingsFormat.type;
94
95 options = {
96 client_api = {
97 ipc_enabled = mkOption {
98 type = types.bool;
99 default = true;
100 description = "veilid-server will respond to Python and other JSON client requests.";
101 };
102 ipc_directory = mkOption {
103 type = types.str;
104 default = "${dataDir}/ipc";
105 description = "IPC directory where file sockets are stored.";
106 };
107 };
108 logging = {
109 system = {
110 enabled = mkOption {
111 type = types.bool;
112 default = true;
113 description = "Events of type 'system' will be logged.";
114 };
115 level = mkOption {
116 type = types.str;
117 default = "info";
118 example = "debug";
119 description = "The minimum priority of system events to be logged.";
120 };
121 };
122 terminal = {
123 enabled = mkOption {
124 type = types.bool;
125 default = false;
126 description = "Events of type 'terminal' will be logged.";
127 };
128 level = mkOption {
129 type = types.str;
130 default = "info";
131 example = "debug";
132 description = "The minimum priority of terminal events to be logged.";
133 };
134 };
135 api = {
136 enabled = mkOption {
137 type = types.bool;
138 default = false;
139 description = "Events of type 'api' will be logged.";
140 };
141 level = mkOption {
142 type = types.str;
143 default = "info";
144 example = "debug";
145 description = "The minimum priority of api events to be logged.";
146 };
147 };
148 };
149 core = {
150 capabilities = {
151 disable = mkOption {
152 type = types.listOf types.str;
153 default = [ ];
154 example = [ "APPM" ];
155 description = "A list of capabilities to disable (for example, DHTV to say you cannot store DHT information).";
156 };
157 };
158 protected_store = {
159 allow_insecure_fallback = mkOption {
160 type = types.bool;
161 default = true;
162 description = "If we can't use system-provided secure storage, should we proceed anyway?";
163 };
164 always_use_insecure_storage = mkOption {
165 type = types.bool;
166 default = true;
167 description = "Should we bypass any attempt to use system-provided secure storage?";
168 };
169 directory = mkOption {
170 type = types.str;
171 default = "${dataDir}/protected_store";
172 description = "The filesystem directory to store your protected store in.";
173 };
174 };
175 table_store = {
176 directory = mkOption {
177 type = types.str;
178 default = "${dataDir}/table_store";
179 description = "The filesystem directory to store your table store within.";
180 };
181 };
182 block_store = {
183 directory = mkOption {
184 type = types.nullOr types.str;
185 default = "${dataDir}/block_store";
186 description = "The filesystem directory to store blocks for the block store.";
187 };
188 };
189 network = {
190 routing_table = {
191 bootstrap = mkOption {
192 type = types.listOf types.str;
193 default = [ "bootstrap.veilid.net" ];
194 description = "Host name of existing well-known Veilid bootstrap servers for the network to connect to.";
195 };
196 node_id = lib.mkOption {
197 type = lib.types.nullOr lib.types.str;
198 default = null;
199 description = "Base64-encoded public key for the node, used as the node's ID.";
200 };
201 };
202 dht = {
203 min_peer_count = mkOption {
204 type = types.number;
205 default = 20;
206 description = "Minimum number of nodes to keep in the peer table.";
207 };
208 };
209 upnp = mkOption {
210 type = types.bool;
211 default = true;
212 description = "Should the app try to improve its incoming network connectivity using UPnP?";
213 };
214 detect_address_changes = mkOption {
215 type = types.bool;
216 default = true;
217 description = "Should veilid-core detect and notify on network address changes?";
218 };
219 };
220 };
221 };
222 };
223 };
224 };
225
226 meta.maintainers = with maintainers; [ figboy9 ];
227}