1 { config, lib, pkgs, ... }:
5 cfg = config.services.tahoe;
8 options.services.tahoe = {
9 introducers = mkOption {
11 type = with types; attrsOf (submodule {
15 description = lib.mdDoc ''
16 The nickname of this Tahoe introducer.
22 description = lib.mdDoc ''
23 The port on which the introducer will listen.
26 tub.location = mkOption {
28 type = types.nullOr types.str;
29 description = lib.mdDoc ''
30 The external location that the introducer should listen on.
32 If specified, the port should be included.
36 default = pkgs.tahoelafs;
37 defaultText = literalExpression "pkgs.tahoelafs";
39 description = lib.mdDoc ''
40 The package to use for the Tahoe LAFS daemon.
45 description = lib.mdDoc ''
46 The Tahoe introducers.
51 type = with types; attrsOf (submodule {
55 description = lib.mdDoc ''
56 The nickname of this Tahoe node.
62 description = lib.mdDoc ''
63 The port on which the tub will listen.
65 This is the correct setting to tweak if you want Tahoe's storage
66 system to listen on a different port.
69 tub.location = mkOption {
71 type = types.nullOr types.str;
72 description = lib.mdDoc ''
73 The external location that the node should listen on.
75 This is the setting to tweak if there are multiple interfaces
76 and you want to alter which interface Tahoe is advertising.
78 If specified, the port should be included.
84 description = lib.mdDoc ''
85 The port on which the Web server will listen.
87 This is the correct setting to tweak if you want Tahoe's WUI to
88 listen on a different port.
91 client.introducer = mkOption {
93 type = types.nullOr types.str;
94 description = lib.mdDoc ''
95 The furl for a Tahoe introducer node.
97 Like all furls, keep this safe and don't share it.
100 client.helper = mkOption {
102 type = types.nullOr types.str;
103 description = lib.mdDoc ''
104 The furl for a Tahoe helper node.
106 Like all furls, keep this safe and don't share it.
109 client.shares.needed = mkOption {
112 description = lib.mdDoc ''
113 The number of shares required to reconstitute a file.
116 client.shares.happy = mkOption {
119 description = lib.mdDoc ''
120 The number of distinct storage nodes required to store
124 client.shares.total = mkOption {
127 description = lib.mdDoc ''
128 The number of shares required to store a file.
131 storage.enable = mkEnableOption (lib.mdDoc "storage service");
132 storage.reservedSpace = mkOption {
135 description = lib.mdDoc ''
136 The amount of filesystem space to not use for storage.
139 helper.enable = mkEnableOption (lib.mdDoc "helper service");
140 sftpd.enable = mkEnableOption (lib.mdDoc "SFTP service");
141 sftpd.port = mkOption {
143 type = types.nullOr types.int;
144 description = lib.mdDoc ''
145 The port on which the SFTP server will listen.
147 This is the correct setting to tweak if you want Tahoe's SFTP
148 daemon to listen on a different port.
151 sftpd.hostPublicKeyFile = mkOption {
153 type = types.nullOr types.path;
154 description = lib.mdDoc ''
155 Path to the SSH host public key.
158 sftpd.hostPrivateKeyFile = mkOption {
160 type = types.nullOr types.path;
161 description = lib.mdDoc ''
162 Path to the SSH host private key.
165 sftpd.accounts.file = mkOption {
167 type = types.nullOr types.path;
168 description = lib.mdDoc ''
169 Path to the accounts file.
172 sftpd.accounts.url = mkOption {
174 type = types.nullOr types.str;
175 description = lib.mdDoc ''
176 URL of the accounts server.
180 default = pkgs.tahoelafs;
181 defaultText = literalExpression "pkgs.tahoelafs";
182 type = types.package;
183 description = lib.mdDoc ''
184 The package to use for the Tahoe LAFS daemon.
189 description = lib.mdDoc ''
195 (mkIf (cfg.introducers != {}) {
197 etc = flip mapAttrs' cfg.introducers (node: settings:
198 nameValuePair "tahoe-lafs/introducer-${node}.cfg" {
201 # This configuration is generated by Nix. Edit at your own
202 # peril; here be dragons.
205 nickname = ${settings.nickname}
206 tub.port = ${toString settings.tub.port}
207 ${optionalString (settings.tub.location != null)
208 "tub.location = ${settings.tub.location}"}
211 # Actually require Tahoe, so that we will have it installed.
212 systemPackages = flip mapAttrsToList cfg.introducers (node: settings:
216 # Open up the firewall.
217 # networking.firewall.allowedTCPPorts = flip mapAttrsToList cfg.introducers
218 # (node: settings: settings.tub.port);
219 systemd.services = flip mapAttrs' cfg.introducers (node: settings:
221 pidfile = "/run/tahoe.introducer-${node}.pid";
222 # This is a directory, but it has no trailing slash. Tahoe commands
223 # get antsy when there's a trailing slash.
224 nodedir = "/var/db/tahoe-lafs/introducer-${node}";
225 in nameValuePair "tahoe.introducer-${node}" {
226 description = "Tahoe LAFS node ${node}";
227 wantedBy = [ "multi-user.target" ];
228 path = [ settings.package ];
230 config.environment.etc."tahoe-lafs/introducer-${node}.cfg".source ];
234 # Believe it or not, Tahoe is very brittle about the order of
235 # arguments to $(tahoe run). The node directory must come first,
236 # and arguments which alter Twisted's behavior come afterwards.
238 ${settings.package}/bin/tahoe run ${lib.escapeShellArg nodedir} --pidfile=${lib.escapeShellArg pidfile}
242 if [ ! -d ${lib.escapeShellArg nodedir} ]; then
243 mkdir -p /var/db/tahoe-lafs
244 # See https://github.com/NixOS/nixpkgs/issues/25273
245 tahoe create-introducer \
246 --hostname="${config.networking.hostName}" \
247 ${lib.escapeShellArg nodedir}
250 # Tahoe has created a predefined tahoe.cfg which we must now
252 # XXX I thought that a symlink would work here, but it doesn't, so
253 # we must do this on every prestart. Fixes welcome.
254 # rm ${nodedir}/tahoe.cfg
255 # ln -s /etc/tahoe-lafs/introducer-${node}.cfg ${nodedir}/tahoe.cfg
256 cp /etc/tahoe-lafs/introducer-"${node}".cfg ${lib.escapeShellArg nodedir}/tahoe.cfg
259 users.users = flip mapAttrs' cfg.introducers (node: _:
260 nameValuePair "tahoe.introducer-${node}" {
261 description = "Tahoe node user for introducer ${node}";
265 (mkIf (cfg.nodes != {}) {
267 etc = flip mapAttrs' cfg.nodes (node: settings:
268 nameValuePair "tahoe-lafs/${node}.cfg" {
271 # This configuration is generated by Nix. Edit at your own
272 # peril; here be dragons.
275 nickname = ${settings.nickname}
276 tub.port = ${toString settings.tub.port}
277 ${optionalString (settings.tub.location != null)
278 "tub.location = ${settings.tub.location}"}
279 # This is a Twisted endpoint. Twisted Web doesn't work on
281 web.port = tcp:${toString settings.web.port}
284 ${optionalString (settings.client.introducer != null)
285 "introducer.furl = ${settings.client.introducer}"}
286 ${optionalString (settings.client.helper != null)
287 "helper.furl = ${settings.client.helper}"}
289 shares.needed = ${toString settings.client.shares.needed}
290 shares.happy = ${toString settings.client.shares.happy}
291 shares.total = ${toString settings.client.shares.total}
294 enabled = ${boolToString settings.storage.enable}
295 reserved_space = ${settings.storage.reservedSpace}
298 enabled = ${boolToString settings.helper.enable}
301 enabled = ${boolToString settings.sftpd.enable}
302 ${optionalString (settings.sftpd.port != null)
303 "port = ${toString settings.sftpd.port}"}
304 ${optionalString (settings.sftpd.hostPublicKeyFile != null)
305 "host_pubkey_file = ${settings.sftpd.hostPublicKeyFile}"}
306 ${optionalString (settings.sftpd.hostPrivateKeyFile != null)
307 "host_privkey_file = ${settings.sftpd.hostPrivateKeyFile}"}
308 ${optionalString (settings.sftpd.accounts.file != null)
309 "accounts.file = ${settings.sftpd.accounts.file}"}
310 ${optionalString (settings.sftpd.accounts.url != null)
311 "accounts.url = ${settings.sftpd.accounts.url}"}
314 # Actually require Tahoe, so that we will have it installed.
315 systemPackages = flip mapAttrsToList cfg.nodes (node: settings:
319 # Open up the firewall.
320 # networking.firewall.allowedTCPPorts = flip mapAttrsToList cfg.nodes
321 # (node: settings: settings.tub.port);
322 systemd.services = flip mapAttrs' cfg.nodes (node: settings:
324 pidfile = "/run/tahoe.${node}.pid";
325 # This is a directory, but it has no trailing slash. Tahoe commands
326 # get antsy when there's a trailing slash.
327 nodedir = "/var/db/tahoe-lafs/${node}";
328 in nameValuePair "tahoe.${node}" {
329 description = "Tahoe LAFS node ${node}";
330 wantedBy = [ "multi-user.target" ];
331 path = [ settings.package ];
333 config.environment.etc."tahoe-lafs/${node}.cfg".source ];
337 # Believe it or not, Tahoe is very brittle about the order of
338 # arguments to $(tahoe run). The node directory must come first,
339 # and arguments which alter Twisted's behavior come afterwards.
341 ${settings.package}/bin/tahoe run ${lib.escapeShellArg nodedir} --pidfile=${lib.escapeShellArg pidfile}
345 if [ ! -d ${lib.escapeShellArg nodedir} ]; then
346 mkdir -p /var/db/tahoe-lafs
347 tahoe create-node --hostname=localhost ${lib.escapeShellArg nodedir}
350 # Tahoe has created a predefined tahoe.cfg which we must now
352 # XXX I thought that a symlink would work here, but it doesn't, so
353 # we must do this on every prestart. Fixes welcome.
354 # rm ${nodedir}/tahoe.cfg
355 # ln -s /etc/tahoe-lafs/${lib.escapeShellArg node}.cfg ${nodedir}/tahoe.cfg
356 cp /etc/tahoe-lafs/${lib.escapeShellArg node}.cfg ${lib.escapeShellArg nodedir}/tahoe.cfg
359 users.users = flip mapAttrs' cfg.nodes (node: _:
360 nameValuePair "tahoe.${node}" {
361 description = "Tahoe node user for node ${node}";