rdma-core: 54.0 -> 55.0 (#364655)
[NixPkgs.git] / nixos / modules / services / networking / resilio.nix
blobcae788a6c018bd729f893f0f78425c94626b66f5
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.resilio;
8   sharedFoldersRecord = map (entry: {
9     dir = entry.directory;
11     use_relay_server = entry.useRelayServer;
12     use_tracker = entry.useTracker;
13     use_dht = entry.useDHT;
15     search_lan = entry.searchLAN;
16     use_sync_trash = entry.useSyncTrash;
17     known_hosts = entry.knownHosts;
18   }) cfg.sharedFolders;
20   configFile = pkgs.writeText "config.json" (builtins.toJSON ({
21     device_name = cfg.deviceName;
22     storage_path = cfg.storagePath;
23     listening_port = cfg.listeningPort;
24     use_gui = false;
25     check_for_updates = cfg.checkForUpdates;
26     use_upnp = cfg.useUpnp;
27     download_limit = cfg.downloadLimit;
28     upload_limit = cfg.uploadLimit;
29     lan_encrypt_data = cfg.encryptLAN;
30   } // optionalAttrs (cfg.directoryRoot != "") { directory_root = cfg.directoryRoot; }
31     // optionalAttrs cfg.enableWebUI {
32     webui = { listen = "${cfg.httpListenAddr}:${toString cfg.httpListenPort}"; } //
33       (optionalAttrs (cfg.httpLogin != "") { login = cfg.httpLogin; }) //
34       (optionalAttrs (cfg.httpPass != "") { password = cfg.httpPass; }) //
35       (optionalAttrs (cfg.apiKey != "") { api_key = cfg.apiKey; });
36   } // optionalAttrs (sharedFoldersRecord != []) {
37     shared_folders = sharedFoldersRecord;
38   }));
40   sharedFoldersSecretFiles = map (entry: {
41     dir = entry.directory;
42     secretFile = if builtins.hasAttr "secret" entry then
43       toString (pkgs.writeTextFile {
44         name = "secret-file";
45         text = entry.secret;
46       })
47     else
48       entry.secretFile;
49   }) cfg.sharedFolders;
51   runConfigPath = "/run/rslsync/config.json";
53   createConfig = pkgs.writeShellScriptBin "create-resilio-config" (
54     if cfg.sharedFolders != [ ] then ''
55       ${pkgs.jq}/bin/jq \
56         '.shared_folders |= map(.secret = $ARGS.named[.dir])' \
57         ${
58           lib.concatMapStringsSep " \\\n  "
59           (entry: ''--arg '${entry.dir}' "$(cat '${entry.secretFile}')"'')
60           sharedFoldersSecretFiles
61         } \
62         <${configFile} \
63         >${runConfigPath}
64     '' else ''
65       # no secrets, passing through config
66       cp ${configFile} ${runConfigPath};
67     ''
68   );
72   options = {
73     services.resilio = {
74       enable = mkOption {
75         type = types.bool;
76         default = false;
77         description = ''
78           If enabled, start the Resilio Sync daemon. Once enabled, you can
79           interact with the service through the Web UI, or configure it in your
80           NixOS configuration.
81         '';
82       };
84       package = mkPackageOption pkgs "resilio-sync" { };
86       deviceName = mkOption {
87         type = types.str;
88         example = "Voltron";
89         default = config.networking.hostName;
90         defaultText = literalExpression "config.networking.hostName";
91         description = ''
92           Name of the Resilio Sync device.
93         '';
94       };
96       listeningPort = mkOption {
97         type = types.int;
98         default = 0;
99         example = 44444;
100         description = ''
101           Listening port. Defaults to 0 which randomizes the port.
102         '';
103       };
105       checkForUpdates = mkOption {
106         type = types.bool;
107         default = true;
108         description = ''
109           Determines whether to check for updates and alert the user
110           about them in the UI.
111         '';
112       };
114       useUpnp = mkOption {
115         type = types.bool;
116         default = true;
117         description = ''
118           Use Universal Plug-n-Play (UPnP)
119         '';
120       };
122       downloadLimit = mkOption {
123         type = types.int;
124         default = 0;
125         example = 1024;
126         description = ''
127           Download speed limit. 0 is unlimited (default).
128         '';
129       };
131       uploadLimit = mkOption {
132         type = types.int;
133         default = 0;
134         example = 1024;
135         description = ''
136           Upload speed limit. 0 is unlimited (default).
137         '';
138       };
140       httpListenAddr = mkOption {
141         type = types.str;
142         default = "[::1]";
143         example = "0.0.0.0";
144         description = ''
145           HTTP address to bind to.
146         '';
147       };
149       httpListenPort = mkOption {
150         type = types.int;
151         default = 9000;
152         description = ''
153           HTTP port to bind on.
154         '';
155       };
157       httpLogin = mkOption {
158         type = types.str;
159         example = "allyourbase";
160         default = "";
161         description = ''
162           HTTP web login username.
163         '';
164       };
166       httpPass = mkOption {
167         type = types.str;
168         example = "arebelongtous";
169         default = "";
170         description = ''
171           HTTP web login password.
172         '';
173       };
175       encryptLAN = mkOption {
176         type = types.bool;
177         default = true;
178         description = "Encrypt LAN data.";
179       };
181       enableWebUI = mkOption {
182         type = types.bool;
183         default = false;
184         description = ''
185           Enable Web UI for administration. Bound to the specified
186           `httpListenAddress` and
187           `httpListenPort`.
188           '';
189       };
191       storagePath = mkOption {
192         type = types.path;
193         default = "/var/lib/resilio-sync/";
194         description = ''
195           Where BitTorrent Sync will store it's database files (containing
196           things like username info and licenses). Generally, you should not
197           need to ever change this.
198         '';
199       };
201       apiKey = mkOption {
202         type = types.str;
203         default = "";
204         description = "API key, which enables the developer API.";
205       };
207       directoryRoot = mkOption {
208         type = types.str;
209         default = "";
210         example = "/media";
211         description = "Default directory to add folders in the web UI.";
212       };
214       sharedFolders = mkOption {
215         default = [];
216         type = types.listOf (types.attrsOf types.anything);
217         example =
218           [ { secretFile     = "/run/resilio-secret";
219               directory      = "/home/user/sync_test";
220               useRelayServer = true;
221               useTracker     = true;
222               useDHT         = false;
223               searchLAN      = true;
224               useSyncTrash   = true;
225               knownHosts     = [
226                 "192.168.1.2:4444"
227                 "192.168.1.3:4444"
228               ];
229             }
230           ];
231         description = ''
232           Shared folder list. If enabled, web UI must be
233           disabled. Secrets can be generated using `rslsync --generate-secret`.
235           If you would like to be able to modify the contents of this
236           directories, it is recommended that you make your user a
237           member of the `rslsync` group.
239           Directories in this list should be in the
240           `rslsync` group, and that group must have
241           write access to the directory. It is also recommended that
242           `chmod g+s` is applied to the directory
243           so that any sub directories created will also belong to
244           the `rslsync` group. Also,
245           `setfacl -d -m group:rslsync:rwx` and
246           `setfacl -m group:rslsync:rwx` should also
247           be applied so that the sub directories are writable by
248           the group.
249         '';
250       };
251     };
252   };
254   config = mkIf cfg.enable {
255     assertions =
256       [ { assertion = cfg.deviceName != "";
257           message   = "Device name cannot be empty.";
258         }
259         { assertion = cfg.enableWebUI -> cfg.sharedFolders == [];
260           message   = "If using shared folders, the web UI cannot be enabled.";
261         }
262         { assertion = cfg.apiKey != "" -> cfg.enableWebUI;
263           message   = "If you're using an API key, you must enable the web server.";
264         }
265       ];
267     users.users.rslsync = {
268       description     = "Resilio Sync Service user";
269       home            = cfg.storagePath;
270       createHome      = true;
271       uid             = config.ids.uids.rslsync;
272       group           = "rslsync";
273     };
275     users.groups.rslsync.gid = config.ids.gids.rslsync;
277     systemd.services.resilio = with pkgs; {
278       description = "Resilio Sync Service";
279       wantedBy    = [ "multi-user.target" ];
280       after       = [ "network.target" ];
281       serviceConfig = {
282         Restart   = "on-abort";
283         UMask     = "0002";
284         User      = "rslsync";
285         RuntimeDirectory = "rslsync";
286         ExecStartPre = "${createConfig}/bin/create-resilio-config";
287         ExecStart = ''
288           ${lib.getExe cfg.package} --nodaemon --config ${runConfigPath}
289         '';
290       };
291     };
292   };
294   meta.maintainers = [ ];