diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix
index 3c58cd9ddade..63b249df735e 100644
--- a/nixos/modules/services/networking/syncthing.nix
+++ b/nixos/modules/services/networking/syncthing.nix
@@ -5,15 +5,16 @@ with lib;
let
cfg = config.services.syncthing;
defaultUser = "syncthing";
+ defaultGroup = defaultUser;
devices = mapAttrsToList (name: device: {
deviceID = device.id;
inherit (device) name addresses introducer;
- }) cfg.declarative.devices;
+ }) cfg.devices;
folders = mapAttrsToList ( _: folder: {
inherit (folder) path id label type;
- devices = map (device: { deviceId = cfg.declarative.devices.${device}.id; }) folder.devices;
+ devices = map (device: { deviceId = cfg.devices.${device}.id; }) folder.devices;
rescanIntervalS = folder.rescanInterval;
fsWatcherEnabled = folder.watch;
fsWatcherDelayS = folder.watchDelay;
@@ -23,7 +24,7 @@ let
}) (filterAttrs (
_: folder:
folder.enable
- ) cfg.declarative.folders);
+ ) cfg.folders);
updateConfig = pkgs.writers.writeDash "merge-syncthing-config" ''
set -efu
@@ -50,9 +51,9 @@ let
# generate the new config by merging with the NixOS config options
new_cfg=$(echo "$old_cfg" | ${pkgs.jq}/bin/jq -c '. * {
- "devices": (${builtins.toJSON devices}${optionalString (! cfg.declarative.overrideDevices) " + .devices"}),
- "folders": (${builtins.toJSON folders}${optionalString (! cfg.declarative.overrideFolders) " + .folders"})
- } * ${builtins.toJSON cfg.declarative.extraOptions}')
+ "devices": (${builtins.toJSON devices}${optionalString (! cfg.overrideDevices) " + .devices"}),
+ "folders": (${builtins.toJSON folders}${optionalString (! cfg.overrideFolders) " + .folders"})
+ } * ${builtins.toJSON cfg.extraOptions}')
# send the new config
curl -X PUT -d "$new_cfg" ${cfg.guiAddress}/rest/config
@@ -68,172 +69,177 @@ in {
options = {
services.syncthing = {
- enable = mkEnableOption ''
- Syncthing - the self-hosted open-source alternative
- to Dropbox and Bittorrent Sync. Initial interface will be
- available on http://127.0.0.1:8384/.
- '';
+ enable = mkEnableOption
+ "Syncthing, a self-hosted open-source alternative to Dropbox and Bittorrent Sync";
- declarative = {
- cert = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- Path to users cert.pem file, will be copied into Syncthing's
- configDir
- '';
- };
+ cert = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = ''
+ Path to the cert.pem file, which will be copied into Syncthing's
+ configDir.
+ '';
+ };
- key = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- Path to users key.pem file, will be copied into Syncthing's
- configDir
- '';
- };
+ key = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = ''
+ Path to the key.pem file, which will be copied into Syncthing's
+ configDir.
+ '';
+ };
- overrideDevices = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Whether to delete the devices which are not configured via the
- declarative.devices option.
- If set to false, devices added via the webinterface will
- persist but will have to be deleted manually.
- '';
- };
+ overrideDevices = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether to delete the devices which are not configured via the
+ devices option.
+ If set to false, devices added via the web
+ interface will persist and will have to be deleted manually.
+ '';
+ };
- devices = mkOption {
- default = {};
- description = ''
- Peers/devices which Syncthing should communicate with.
- '';
- example = {
- bigbox = {
- id = "7CFNTQM-IMTJBHJ-3UWRDIU-ZGQJFR6-VCXZ3NB-XUH3KZO-N52ITXR-LAIYUAU";
- addresses = [ "tcp://192.168.0.10:51820" ];
- };
+ devices = mkOption {
+ default = {};
+ description = ''
+ Peers/devices which Syncthing should communicate with.
+
+ Note that you can still add devices manually, but those changes
+ will be reverted on restart if overrideDevices
+ is enabled.
+ '';
+ example = {
+ bigbox = {
+ id = "7CFNTQM-IMTJBHJ-3UWRDIU-ZGQJFR6-VCXZ3NB-XUH3KZO-N52ITXR-LAIYUAU";
+ addresses = [ "tcp://192.168.0.10:51820" ];
};
- type = types.attrsOf (types.submodule ({ name, ... }: {
- options = {
-
- name = mkOption {
- type = types.str;
- default = name;
- description = ''
- Name of the device
- '';
- };
-
- addresses = mkOption {
- type = types.listOf types.str;
- default = [];
- description = ''
- The addresses used to connect to the device.
- If this is let empty, dynamic configuration is attempted
- '';
- };
-
- id = mkOption {
- type = types.str;
- description = ''
- The id of the other peer, this is mandatory. It's documented at
- https://docs.syncthing.net/dev/device-ids.html
- '';
- };
-
- introducer = mkOption {
- type = types.bool;
- default = false;
- description = ''
- If the device should act as an introducer and be allowed
- to add folders on this computer.
- '';
- };
+ };
+ type = types.attrsOf (types.submodule ({ name, ... }: {
+ options = {
+ name = mkOption {
+ type = types.str;
+ default = name;
+ description = ''
+ The name of the device.
+ '';
};
- }));
- };
- overrideFolders = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Whether to delete the folders which are not configured via the
- declarative.folders option.
- If set to false, folders added via the webinterface will persist
- but will have to be deleted manually.
- '';
- };
+ addresses = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ description = ''
+ The addresses used to connect to the device.
+ If this is left empty, dynamic configuration is attempted.
+ '';
+ };
- folders = mkOption {
- default = {};
- description = ''
- Folders which should be shared by Syncthing.
- '';
- example = literalExample ''
- {
- "/home/user/sync" = {
- id = "syncme";
- devices = [ "bigbox" ];
- };
- }
- '';
- type = types.attrsOf (types.submodule ({ name, ... }: {
- options = {
+ id = mkOption {
+ type = types.str;
+ description = ''
+ The device ID. See .
+ '';
+ };
- enable = mkOption {
- type = types.bool;
- default = true;
- description = ''
- share this folder.
- This option is useful when you want to define all folders
- in one place, but not every machine should share all folders.
- '';
- };
+ introducer = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether the device should act as an introducer and be allowed
+ to add folders on this computer.
+ See .
+ '';
+ };
- path = mkOption {
- type = types.str;
- default = name;
- description = ''
- The path to the folder which should be shared.
- '';
- };
+ };
+ }));
+ };
- id = mkOption {
- type = types.str;
- default = name;
- description = ''
- The id of the folder. Must be the same on all devices.
- '';
- };
+ overrideFolders = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether to delete the folders which are not configured via the
+ folders option.
+ If set to false, folders added via the web
+ interface will persist and will have to be deleted manually.
+ '';
+ };
- label = mkOption {
- type = types.str;
- default = name;
- description = ''
- The label of the folder.
- '';
- };
+ folders = mkOption {
+ default = {};
+ description = ''
+ Folders which should be shared by Syncthing.
- devices = mkOption {
- type = types.listOf types.str;
- default = [];
- description = ''
- The devices this folder should be shared with. Must be defined
- in the declarative.devices attribute.
- '';
- };
+ Note that you can still add devices manually, but those changes
+ will be reverted on restart if overrideDevices
+ is enabled.
+ '';
+ example = literalExample ''
+ {
+ "/home/user/sync" = {
+ id = "syncme";
+ devices = [ "bigbox" ];
+ };
+ }
+ '';
+ type = types.attrsOf (types.submodule ({ name, ... }: {
+ options = {
- versioning = mkOption {
- default = null;
- description = ''
- How to keep changed/deleted files with Syncthing.
- There are 4 different types of versioning with different parameters.
- See https://docs.syncthing.net/users/versioning.html
- '';
- example = [
+ enable = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether to share this folder.
+ This option is useful when you want to define all folders
+ in one place, but not every machine should share all folders.
+ '';
+ };
+
+ path = mkOption {
+ type = types.str;
+ default = name;
+ description = ''
+ The path to the folder which should be shared.
+ '';
+ };
+
+ id = mkOption {
+ type = types.str;
+ default = name;
+ description = ''
+ The ID of the folder. Must be the same on all devices.
+ '';
+ };
+
+ label = mkOption {
+ type = types.str;
+ default = name;
+ description = ''
+ The label of the folder.
+ '';
+ };
+
+ devices = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ description = ''
+ The devices this folder should be shared with. Each device must
+ be defined in the devices option.
+ '';
+ };
+
+ versioning = mkOption {
+ default = null;
+ description = ''
+ How to keep changed/deleted files with Syncthing.
+ There are 4 different types of versioning with different parameters.
+ See .
+ '';
+ example = literalExample ''
+ [
{
versioning = {
type = "simple";
@@ -259,98 +265,99 @@ in {
{
versioning = {
type = "external";
- params.versionsPath = pkgs.writers.writeBash "backup" ''
+ params.versionsPath = pkgs.writers.writeBash "backup" '''
folderpath="$1"
filepath="$2"
rm -rf "$folderpath/$filepath"
- '';
+ ''';
};
}
- ];
- type = with types; nullOr (submodule {
- options = {
- type = mkOption {
- type = enum [ "external" "simple" "staggered" "trashcan" ];
- description = ''
- Type of versioning.
- See https://docs.syncthing.net/users/versioning.html
- '';
- };
- params = mkOption {
- type = attrsOf (either str path);
- description = ''
- Parameters for versioning. Structure depends on versioning.type.
- See https://docs.syncthing.net/users/versioning.html
- '';
- };
+ ]
+ '';
+ type = with types; nullOr (submodule {
+ options = {
+ type = mkOption {
+ type = enum [ "external" "simple" "staggered" "trashcan" ];
+ description = ''
+ The type of versioning.
+ See .
+ '';
};
- });
- };
-
- rescanInterval = mkOption {
- type = types.int;
- default = 3600;
- description = ''
- How often the folders should be rescaned for changes.
- '';
- };
-
- type = mkOption {
- type = types.enum [ "sendreceive" "sendonly" "receiveonly" ];
- default = "sendreceive";
- description = ''
- Whether to send only changes from this folder, only receive them
- or propagate both.
- '';
- };
-
- watch = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Whether the folder should be watched for changes by inotify.
- '';
- };
-
- watchDelay = mkOption {
- type = types.int;
- default = 10;
- description = ''
- The delay after an inotify event is triggered.
- '';
- };
-
- ignorePerms = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Whether to propagate permission changes.
- '';
- };
-
- ignoreDelete = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Whether to delete files in destination. See
- upstream's docs.
- '';
- };
+ params = mkOption {
+ type = attrsOf (either str path);
+ description = ''
+ The parameters for versioning. Structure depends on
+ versioning.type.
+ See .
+ '';
+ };
+ };
+ });
};
- }));
- };
- extraOptions = mkOption {
- type = types.addCheck (pkgs.formats.json {}).type isAttrs;
- default = {};
- description = ''
- Extra configuration options for Syncthing.
- '';
- example = {
- options.localAnnounceEnabled = false;
- gui.theme = "black";
+ rescanInterval = mkOption {
+ type = types.int;
+ default = 3600;
+ description = ''
+ How often the folder should be rescanned for changes.
+ '';
+ };
+
+ type = mkOption {
+ type = types.enum [ "sendreceive" "sendonly" "receiveonly" ];
+ default = "sendreceive";
+ description = ''
+ Whether to only send changes for this folder, only receive them
+ or both.
+ '';
+ };
+
+ watch = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether the folder should be watched for changes by inotify.
+ '';
+ };
+
+ watchDelay = mkOption {
+ type = types.int;
+ default = 10;
+ description = ''
+ The delay after an inotify event is triggered.
+ '';
+ };
+
+ ignorePerms = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether to ignore permission changes.
+ '';
+ };
+
+ ignoreDelete = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to skip deleting files that are deleted by peers.
+ See .
+ '';
+ };
};
+ }));
+ };
+
+ extraOptions = mkOption {
+ type = types.addCheck (pkgs.formats.json {}).type isAttrs;
+ default = {};
+ description = ''
+ Extra configuration options for Syncthing.
+ See .
+ '';
+ example = {
+ options.localAnnounceEnabled = false;
+ gui.theme = "black";
};
};
@@ -358,31 +365,35 @@ in {
type = types.str;
default = "127.0.0.1:8384";
description = ''
- Address to serve the GUI.
+ The address to serve the web interface at.
'';
};
systemService = mkOption {
type = types.bool;
default = true;
- description = "Auto launch Syncthing as a system service.";
+ description = ''
+ Whether to auto-launch Syncthing as a system service.
+ '';
};
user = mkOption {
type = types.str;
default = defaultUser;
+ example = "yourUser";
description = ''
- Syncthing will be run under this user (user will be created if it doesn't exist.
- This can be your user name).
+ The user to run Syncthing as.
+ By default, a user named ${defaultUser} will be created.
'';
};
group = mkOption {
type = types.str;
- default = defaultUser;
+ default = defaultGroup;
+ example = "yourGroup";
description = ''
- Syncthing will be run under this group (group will not be created if it doesn't exist.
- This can be your user name).
+ The group to run Syncthing under.
+ By default, a group named ${defaultGroup} will be created.
'';
};
@@ -391,63 +402,67 @@ in {
default = null;
example = "socks5://address.com:1234";
description = ''
- Overwrites all_proxy environment variable for the Syncthing process to
- the given value. This is normaly used to let relay client connect
- through SOCKS5 proxy server.
+ Overwrites the all_proxy environment variable for the Syncthing process to
+ the given value. This is normally used to let Syncthing connect
+ through a SOCKS5 proxy server.
+ See .
'';
};
dataDir = mkOption {
type = types.path;
default = "/var/lib/syncthing";
+ example = "/home/yourUser";
description = ''
- Path where synced directories will exist.
+ The path where synchronised directories will exist.
'';
};
- configDir = mkOption {
+ configDir = let
+ cond = versionAtLeast config.system.stateVersion "19.03";
+ in mkOption {
type = types.path;
description = ''
- Path where the settings and keys will exist.
+ The path where the settings and keys will exist.
'';
- default =
- let
- nixos = config.system.stateVersion;
- cond = versionAtLeast nixos "19.03";
- in cfg.dataDir + (optionalString cond "/.config/syncthing");
+ default = cfg.dataDir + (optionalString cond "/.config/syncthing");
+ defaultText = literalExample "dataDir${optionalString cond " + \"/.config/syncthing\""}";
};
openDefaultPorts = mkOption {
type = types.bool;
default = false;
- example = literalExample "true";
+ example = true;
description = ''
- Open the default ports in the firewall:
- - TCP 22000 for transfers
- - UDP 21027 for discovery
- If multiple users are running Syncthing on this machine, you will need to manually open a set of ports for each instance and leave this disabled.
- Alternatively, if are running only a single instance on this machine using the default ports, enable this.
+ Whether to open the default ports in the firewall: TCP 22000 for transfers
+ and UDP 21027 for discovery.
+
+ If multiple users are running Syncthing on this machine, you will need
+ to manually open a set of ports for each instance and leave this disabled.
+ Alternatively, if you are running only a single instance on this machine
+ using the default ports, enable this.
'';
};
package = mkOption {
type = types.package;
default = pkgs.syncthing;
- defaultText = "pkgs.syncthing";
- example = literalExample "pkgs.syncthing";
+ defaultText = literalExample "pkgs.syncthing";
description = ''
- Syncthing package to use.
+ The Syncthing package to use.
'';
};
};
};
imports = [
- (mkRemovedOptionModule ["services" "syncthing" "useInotify"] ''
+ (mkRemovedOptionModule [ "services" "syncthing" "useInotify" ] ''
This option was removed because Syncthing now has the inotify functionality included under the name "fswatcher".
- It can be enabled on a per-folder basis through the webinterface.
+ It can be enabled on a per-folder basis through the web interface.
'')
- ];
+ ] ++ map (o:
+ mkRenamedOptionModule [ "services" "syncthing" "declarative" o ] [ "services" "syncthing" o ]
+ ) [ "cert" "key" "devices" "folders" "overrideDevices" "overrideFolders" "extraOptions"];
###### implementation
@@ -470,8 +485,8 @@ in {
};
};
- users.groups = mkIf (cfg.systemService && cfg.group == defaultUser) {
- ${defaultUser}.gid =
+ users.groups = mkIf (cfg.systemService && cfg.group == defaultGroup) {
+ ${defaultGroup}.gid =
config.ids.gids.syncthing;
};
@@ -491,14 +506,14 @@ in {
RestartForceExitStatus="3 4";
User = cfg.user;
Group = cfg.group;
- ExecStartPre = mkIf (cfg.declarative.cert != null || cfg.declarative.key != null)
+ ExecStartPre = mkIf (cfg.cert != null || cfg.key != null)
"+${pkgs.writers.writeBash "syncthing-copy-keys" ''
install -dm700 -o ${cfg.user} -g ${cfg.group} ${cfg.configDir}
- ${optionalString (cfg.declarative.cert != null) ''
- install -Dm400 -o ${cfg.user} -g ${cfg.group} ${toString cfg.declarative.cert} ${cfg.configDir}/cert.pem
+ ${optionalString (cfg.cert != null) ''
+ install -Dm400 -o ${cfg.user} -g ${cfg.group} ${toString cfg.cert} ${cfg.configDir}/cert.pem
''}
- ${optionalString (cfg.declarative.key != null) ''
- install -Dm400 -o ${cfg.user} -g ${cfg.group} ${toString cfg.declarative.key} ${cfg.configDir}/key.pem
+ ${optionalString (cfg.key != null) ''
+ install -Dm400 -o ${cfg.user} -g ${cfg.group} ${toString cfg.key} ${cfg.configDir}/key.pem
''}
''}"
;
@@ -529,7 +544,7 @@ in {
};
};
syncthing-init = mkIf (
- cfg.declarative.devices != {} || cfg.declarative.folders != {} || cfg.declarative.extraOptions != {}
+ cfg.devices != {} || cfg.folders != {} || cfg.extraOptions != {}
) {
description = "Syncthing configuration updater";
after = [ "syncthing.service" ];
diff --git a/nixos/tests/syncthing-init.nix b/nixos/tests/syncthing-init.nix
index f359f0af1c22..8b60ad7faf09 100644
--- a/nixos/tests/syncthing-init.nix
+++ b/nixos/tests/syncthing-init.nix
@@ -9,16 +9,14 @@ in {
machine = {
services.syncthing = {
enable = true;
- declarative = {
- devices.testDevice = {
- id = testId;
- };
- folders.testFolder = {
- path = "/tmp/test";
- devices = [ "testDevice" ];
- };
- extraOptions.gui.user = "guiUser";
+ devices.testDevice = {
+ id = testId;
};
+ folders.testFolder = {
+ path = "/tmp/test";
+ devices = [ "testDevice" ];
+ };
+ extraOptions.gui.user = "guiUser";
};
};