1 { config, lib, pkgs, ... }:
6 cfg = config.services.resilio;
8 resilioSync = pkgs.resilio-sync;
10 sharedFoldersRecord = map (entry: {
11 dir = entry.directory;
13 use_relay_server = entry.useRelayServer;
14 use_tracker = entry.useTracker;
15 use_dht = entry.useDHT;
17 search_lan = entry.searchLAN;
18 use_sync_trash = entry.useSyncTrash;
19 known_hosts = entry.knownHosts;
22 configFile = pkgs.writeText "config.json" (builtins.toJSON ({
23 device_name = cfg.deviceName;
24 storage_path = cfg.storagePath;
25 listening_port = cfg.listeningPort;
27 check_for_updates = cfg.checkForUpdates;
28 use_upnp = cfg.useUpnp;
29 download_limit = cfg.downloadLimit;
30 upload_limit = cfg.uploadLimit;
31 lan_encrypt_data = cfg.encryptLAN;
32 } // optionalAttrs (cfg.directoryRoot != "") { directory_root = cfg.directoryRoot; }
33 // optionalAttrs cfg.enableWebUI {
34 webui = { listen = "${cfg.httpListenAddr}:${toString cfg.httpListenPort}"; } //
35 (optionalAttrs (cfg.httpLogin != "") { login = cfg.httpLogin; }) //
36 (optionalAttrs (cfg.httpPass != "") { password = cfg.httpPass; }) //
37 (optionalAttrs (cfg.apiKey != "") { api_key = cfg.apiKey; });
38 } // optionalAttrs (sharedFoldersRecord != []) {
39 shared_folders = sharedFoldersRecord;
42 sharedFoldersSecretFiles = map (entry: {
43 dir = entry.directory;
44 secretFile = if builtins.hasAttr "secret" entry then
45 toString (pkgs.writeTextFile {
53 runConfigPath = "/run/rslsync/config.json";
55 createConfig = pkgs.writeShellScriptBin "create-resilio-config" (
56 if cfg.sharedFolders != [ ] then ''
58 '.shared_folders |= map(.secret = $ARGS.named[.dir])' \
60 lib.concatMapStringsSep " \\\n "
61 (entry: ''--arg '${entry.dir}' "$(cat '${entry.secretFile}')"'')
62 sharedFoldersSecretFiles
67 # no secrets, passing through config
68 cp ${configFile} ${runConfigPath};
80 If enabled, start the Resilio Sync daemon. Once enabled, you can
81 interact with the service through the Web UI, or configure it in your
86 deviceName = mkOption {
89 default = config.networking.hostName;
90 defaultText = literalExpression "config.networking.hostName";
92 Name of the Resilio Sync device.
96 listeningPort = mkOption {
101 Listening port. Defaults to 0 which randomizes the port.
105 checkForUpdates = mkOption {
109 Determines whether to check for updates and alert the user
110 about them in the UI.
118 Use Universal Plug-n-Play (UPnP)
122 downloadLimit = mkOption {
127 Download speed limit. 0 is unlimited (default).
131 uploadLimit = mkOption {
136 Upload speed limit. 0 is unlimited (default).
140 httpListenAddr = mkOption {
145 HTTP address to bind to.
149 httpListenPort = mkOption {
153 HTTP port to bind on.
157 httpLogin = mkOption {
159 example = "allyourbase";
162 HTTP web login username.
166 httpPass = mkOption {
168 example = "arebelongtous";
171 HTTP web login password.
175 encryptLAN = mkOption {
178 description = "Encrypt LAN data.";
181 enableWebUI = mkOption {
185 Enable Web UI for administration. Bound to the specified
186 `httpListenAddress` and
191 storagePath = mkOption {
193 default = "/var/lib/resilio-sync/";
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.
204 description = "API key, which enables the developer API.";
207 directoryRoot = mkOption {
211 description = "Default directory to add folders in the web UI.";
214 sharedFolders = mkOption {
216 type = types.listOf (types.attrsOf types.anything);
218 [ { secretFile = "/run/resilio-secret";
219 directory = "/home/user/sync_test";
220 useRelayServer = true;
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
254 config = mkIf cfg.enable {
256 [ { assertion = cfg.deviceName != "";
257 message = "Device name cannot be empty.";
259 { assertion = cfg.enableWebUI -> cfg.sharedFolders == [];
260 message = "If using shared folders, the web UI cannot be enabled.";
262 { assertion = cfg.apiKey != "" -> cfg.enableWebUI;
263 message = "If you're using an API key, you must enable the web server.";
267 users.users.rslsync = {
268 description = "Resilio Sync Service user";
269 home = cfg.storagePath;
271 uid = config.ids.uids.rslsync;
275 users.groups.rslsync = {};
277 systemd.services.resilio = with pkgs; {
278 description = "Resilio Sync Service";
279 wantedBy = [ "multi-user.target" ];
280 after = [ "network.target" ];
282 Restart = "on-abort";
285 RuntimeDirectory = "rslsync";
286 ExecStartPre = "${createConfig}/bin/create-resilio-config";
288 ${resilioSync}/bin/rslsync --nodaemon --config ${runConfigPath}
294 meta.maintainers = [ ];