services: syncthing: Add support for declarative configuration.

* gnu/services/syncthing.scm: (syncthing-config-file, syncthing-folder,
syncthing-device, syncthing-folder-device): New records.
(syncthing-service-type): Add special-files-service-type extension for
the config file.
(syncthing-files-service): Add service to create config file.
* gnu/home/services/syncthing.scm: (home-syncthing-service-type):
Extend home-files-services-type and re-exported more things from
gnu/services/syncthing.scm.
* doc/guix.texi: (syncthing-service-type): Document changes.

Change-Id: I87eeba1ee1fdada8f29c2ee881fbc6bc4113dde9
Signed-off-by: Leo Famulari <leo@famulari.name>
This commit is contained in:
Zacchaeus 2025-02-16 12:56:16 -05:00 committed by Leo Famulari
parent ad74dedb9f
commit 651f8765b6
No known key found for this signature in database
GPG key ID: 6AAC1963757F47FF
3 changed files with 838 additions and 33 deletions

View file

@ -137,6 +137,7 @@ Copyright @copyright{} 2024 Sharlatan Hellseher@*
Copyright @copyright{} 2024 45mg@*
Copyright @copyright{} 2025 Sören Tempel@*
Copyright @copyright{} 2025 Rostislav Svoboda@*
Copyright @copyright{} 2025 Zacchaeus@*
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
@ -22738,7 +22739,7 @@ client.
The @code{(gnu services syncthing)} module provides the following services:
@cindex syncthing
You might want a syncthing daemon if you have files between two or more
You might want a Syncthing daemon if you have files between two or more
computers and want to sync them in real time, safely protected from
prying eyes.
@ -22784,12 +22785,343 @@ The group as which the Syncthing service is to be run.
This assumes that the specified group exists.
@item @code{home} (default: @var{#f})
Common configuration and data directory. The default configuration
directory is @file{$HOME} of the specified Syncthing @code{user}.
Sets the @code{HOME} variable for the Syncthing daemon. The default is
@file{$HOME} of the specified Syncthing @code{user}.
@item @code{config-file} (default: @var{#f})
Either a file-like object that resolves to a Syncthing configuration XML
file, or a @code{syncthing-config-file} record (see below). If set to
@code{#f}, Guix will not try to generate a config file, and Syncthing
will generate a default configuration which will not be touched on
reconfigure. Specifying this in a system service moves Syncthing's
common configuration and data directory (@code{--home} in
@uref{https://docs.syncthing.net/users/syncthing.html}) to
@file{/var/lib/syncthing-<user>}.
@end table
@end deftp
This section documents a subset of the Syncthing configuration
options—specifically those related to Guix or those affecting how your
computer will connect to other computers over the network (such as
Syncthing relays or discovery servers). The configuration is fully
documented in the upstream
@uref{https://docs.syncthing.net/users/config.html, Syncthing config
documentation}; camelCase there is converted to kebab-case here. If you
are migrating from a Syncthing-managed configuration to one managed by
Guix, you can check what changes were introduced by @code{diff}ing the
respective @file{config.xml} files. Note that you will need to add
whitespace with 4-space indentation to the file generated by Guix, using
the @code{xmllint} program from the @code{libxml2} package like so:
@example
XMLLINT_INDENT=" " xmllint --format /path/to/new/config.xml | diff /path/to/old/config.xml -
@end example
When generating a configuration file through Guix, you can still
temporarily modify Syncthing from the GUI or through @code{introducer}
and @code{autoAcceptFolders} mechanisms, but such changes will be reset
on reconfigure.
@deftp {Data Type} syncthing-config-file
Data type representing the configuration file read by the Syncthing
daemon.
@table @asis
@item @code{folders} (default: @var{(list (syncthing-folder (id "default") (label "Default Folder") (path "~/Sync")))}
The default here is the same as Syncthing's default. The value should
be a list of @code{syncthing-folder}s.
@item @code{devices} (default: @var{'()}
This should be a list of @code{syncthing-device}s. Guix will
automatically add any devices specified in any `folders' to this list.
There are instances when you want to connect to a device despite not
(initially) sharing any folders (such as a device with
autoAcceptFolders). In such instances, you should specify those devices
here. If multiple versions of the same device (as determined by
comparing device ID) are discovered, the one in this list is
prioritized. Otherwise, the first instance in the first folder is used.
@item @code{gui-enabled} (default: @var{"true"})
By default, any user on the computer can access the GUI and make changes
to Syncthing. If you leave this enabled, you should probably set
@code{gui-user} and @code{gui-password} (see below).
@item @code{gui-tls} (default: @var{"false"})
@item @code{gui-debugging} (default: @var{"false"})
@item @code{gui-send-basic-auth-prompt} (default: @var{"false"})
@item @code{gui-address} (default: @var{"127.0.0.1:8384"})
@item @code{gui-user} (default: @var{#f})
@item @code{gui-password} (default: @var{#f})
A bcrypt hash of the GUI password. Remember that this will be globally
exposed in @file{/gnu/store}.
@item @code{gui-apikey} (default: @var{#f})
You must specify this to use the Syncthing REST interface. This key is
kept in @file{/gnu/store} and is accessible to all users of the system.
@item @code{gui-theme} (default: @var{"default"})
@item @code{ldap-enabled} (default: @var{#f})
@item @code{ldap-address} (default: @var{""})
@item @code{ldap-bind-dn} (default: @var{""})
@item @code{ldap-transport} (default: @var{""})
@item @code{ldap-insecure-skip-verify} (default: @var{""})
@item @code{ldap-search-base-dn} (default: @var{""})
@item @code{ldap-search-filter} (default: @var{""})
@item @code{listen-address} (default: @var{"default"})
@item @code{global-announce-server} (default: @var{"default"})
@item @code{global-announce-enabled} (default: @var{"true"})
Global discovery servers can be used to help connect devices at unknown
IP addresses by storing the last known IP address.
@item @code{local-announce-enabled} (default: @var{"true"})
This makes devices find each other very easily on the same LAN. Often,
this will allow you to just plug an Ethernet between two devices, or
connect one device to the other's hotspot and start syncing.
@item @code{local-announce-port} (default: @var{"21027"})
@item @code{local-announce-mcaddr} (default: @var{"[ff12::8384]:21027"})
@item @code{max-send-kbps} (default: @var{"0"})
@item @code{max-recv-kbps} (default: @var{"0"})
@item @code{reconnection-interval-s} (default: @var{"60"})
@item @code{relays-enabled} (default: @var{"true"})
This option allows your Syncthing instance to use a global network of
@uref{https://docs.syncthing.net/users/relaying.html, relays} to enable
syncing between devices when all other methods fail. As always,
Syncthing traffic is encrypted in transport and the relays are unable to
decrypt it.
@item @code{relay-reconnect-interval-m} (default: @var{"10"})
@item @code{start-browser} (default: @var{"true"})
@item @code{nat-enabled} (default: @var{"true"})
@item @code{nat-lease-minutes} (default: @var{"60"})
@item @code{nat-renewal-minutes} (default: @var{"30"})
@item @code{nat-timeout-seconds} (default: @var{"10"})
@item @code{ur-accepted} (default: @var{"0"})
Options whose names begin with `ur-' control usage reporting. Set to -1
to disable, or to a positive value to enable. The default (0) disables
reporting, but causes a usage reporting consent prompt to be displayed
in the Syncthing GUI.
@item @code{ur-seen} (default: @var{"0"})
@item @code{ur-unique-id} (default: @var{""})
@item @code{ur-url} (default: @var{"https://data.syncthing.net/newdata"})
@item @code{ur-post-insecurely} (default: @var{"false"})
@item @code{ur-initial-delay-s} (default: @var{"1800"})
@item @code{auto-upgrade-interval-h} (default: @var{"12"})
@item @code{upgrade-to-pre-releases} (default: @var{"false"})
@item @code{keep-temporaries-h} (default: @var{"24"})
@item @code{cache-ignored-files} (default: @var{"false"})
@item @code{progress-update-interval-s} (default: @var{"5"})
@item @code{limit-bandwidth-in-lan} (default: @var{"false"})
@item @code{min-home-disk-free-unit} (default: @var{"%"})
@item @code{min-home-disk-free} (default: @var{"1"})
@item @code{releases-url} (default: @var{"https://upgrades.syncthing.net/meta.json"})
@item @code{overwrite-remote-device-names-on-connect} (default: @var{"false"})
@item @code{temp-index-min-blocks} (default: @var{"10"})
@item @code{unacked-notification-id} (default: @var{"authenticationUserAndPassword"})
@item @code{traffic-class} (default: @var{"0"})
@item @code{set-low-priority} (default: @var{"true"})
@item @code{max-folder-concurrency} (default: @var{"0"})
@item @code{crash-reporting-url} (default: @var{"https://crash.syncthing.net/newcrash"})
@item @code{crash-reporting-enabled} (default: @var{"true"})
@item @code{stun-keepalive-start-s} (default: @var{"180"})
@item @code{stun-keepalive-min-s} (default: @var{"20"})
@item @code{stun-server} (default: @var{"default"})
@item @code{database-tuning} (default: @var{"auto"})
@item @code{max-concurrent-incoming-request-kib} (default: @var{"0"})
@item @code{announce-lan-addresses} (default: @var{"true"})
@item @code{send-full-index-on-upgrade} (default: @var{"false"})
@item @code{connection-limit-enough} (default: @var{"0"})
@item @code{connection-limit-max} (default: @var{"0"})
@item @code{insecure-allow-old-tls-versions} (default: @var{"false"})
@item @code{connection-priority-tcp-lan} (default: @var{"10"})
@item @code{connection-priority-quic-lan} (default: @var{"20"})
@item @code{connection-priority-tcp-wan} (default: @var{"30"})
@item @code{connection-priority-quic-wan} (default: @var{"40"})
@item @code{connection-priority-relay} (default: @var{"50"})
@item @code{connection-priority-upgrade-threshold} (default: @var{"0"})
@item @code{default-folder} (default: @var{(syncthing-folder (label ""))})
@item @code{default-device} (default: @var{(syncthing-device (id ""))})
@item @code{default-ignores} (default: @var{"")})
Options whose names begin with `default-' above do not affect folders
and devices added through the Guix configuration interface. They will,
however, affect folders and devices that are added through the Syncthing
GUI, by an @code{introducer}, or a device with
@code{auto-accept-folders}.
@end table
@end deftp
@deftp {Data Type} syncthing-folder
Data type representing a folder to be synchronized.
@table @asis
@item @code{id} (default: @var{#f})
This ID cannot match the ID of any other folder on this device. If left
unspecified, it will default to the label (see below).
@item @code{label}
A human readable label for the folder.
@item @code{path}
The path at which to store this folder.
@item @code{type} (default: @var{"sendreceive"})
@item @code{rescan-interval-s} (default: @var{"3600"})
@item @code{fs-watcher-enabled} (default: @var{"true"})
@item @code{fs-watcher-delay-s} (default: @var{"10"})
@item @code{ignore-perms} (default: @var{"false"})
@item @code{auto-normalize} (default: @var{"true"})
@item @code{devices} (default: @var{'()})
This should be a list of other Syncthing devices. You do not need to
specify the current device. Each device can be listed as a a
@code{syncthing-device} record or a @code{syncthing-folder-device}
record if you want files to be encrypted on disk. See below.
@item @code{filesystem-type} (default: @var{"basic"})
@item @code{min-disk-free-unit} (default: @var{"%"})
@item @code{min-disk-free} (default: @var{"1"})
@item @code{versioning-type} (default: @var{#f})
@item @code{versioning-fs-path} (default: @var{""})
@item @code{versioning-fs-type} (default: @var{"basic"})
@item @code{versioning-cleanup-interval-s} (default: @var{"3600"})
@item @code{versioning-cleanout-days} (default: @var{#f})
@item @code{versioning-keep} (default: @var{#f})
@item @code{versioning-max-age} (default: @var{#f})
@item @code{versioning-command} (default: @var{#f})
@item @code{copiers} (default: @var{"0"})
@item @code{puller-max-pending-kib} (default: @var{"0"})
@item @code{hashers} (default: @var{"0"})
@item @code{order} (default: @var{"random"})
@item @code{ignore-delete} (default: @var{"false"})
@item @code{scan-progress-interval-s} (default: @var{"0"})
@item @code{puller-pause-s} (default: @var{"0"})
@item @code{max-conflicts} (default: @var{"10"})
@item @code{disable-sparse-files} (default: @var{"false"})
@item @code{disable-temp-indexes} (default: @var{"false"})
@item @code{paused} (default: @var{"false"})
@item @code{weak-hash-threshold-pct} (default: @var{"25"})
@item @code{marker-name} (default: @var{".stfolder"})
@item @code{copy-ownership-from-parent} (default: @var{"false"})
@item @code{mod-time-window-s} (default: @var{"0"})
@item @code{max-concurrent-writes} (default: @var{"2"})
@item @code{disable-fsync} (default: @var{"false"})
@item @code{block-pull-order} (default: @var{"standard"})
@item @code{copy-range-method} (default: @var{"standard"})
@item @code{case-sensitive-fs} (default: @var{"false"})
@item @code{junctions-as-dirs} (default: @var{"false"})
@item @code{sync-ownership} (default: @var{"false"})
@item @code{send-ownership} (default: @var{"false"})
@item @code{sync-xattrs} (default: @var{"false"})
@item @code{send-xattrs} (default: @var{"false"})
@item @code{xattr-filter-max-single-entry-size} (default: @var{"1024"})
@item @code{xattr-filter-max-total-size} (default: @var{"4096")})
@end table
@end deftp
@deftp {Data Type} syncthing-device
Data type representing a device to synchronize folders with.
@table @asis
@item @code{id}
A long hash representing the keys generated by Syncthing on the first
launch. You can obtain this from the Syncthing GUI or by inspecting an
existing Syncthing configuration file.
@item @code{name} (default: @var{""})
A human readable device name for viewing in the GUI or in Scheme.
@item @code{compression} (default: @var{"metadata"})
@item @code{introducer} (default: @var{"false"})
@item @code{skip-introduction-removals} (default: @var{"false"})
@item @code{introduced-by} (default: @var{""})
@item @code{addresses} (default: @var{'("dynamic")})
List of addresses at which to search for this device. When the special
value ``dynamic'' is included, Syncthing will search for the device
locally as well as via the Syncthing project's
@uref{https://docs.syncthing.net/users/security.html#global-discovery,
global discovery} servers.
@item @code{paused} (default: @var{"false"})
@item @code{auto-accept-folders} (default: @var{"false"})
@item @code{max-send-kbps} (default: @var{"0"})
@item @code{max-recv-kbps} (default: @var{"0"})
@item @code{max-request-kib} (default: @var{"0"})
@item @code{untrusted} (default: @var{"false"})
@item @code{remote-gui-port} (default: @var{"0"})
@item @code{num-connections} (default: @var{"0")})
@end table
@end deftp
@deftp {Data Type} syncthing-folder-device
This data type offers two folder-specific device options:
@code{introduced-by} and @code{encryption-password}.
@code{syncthing-folder-device} corresponds to the
@uref{https://docs.syncthing.net/users/config.html#config-option-folder.device,
`device'} option in the upstream `folder' element.
If you don't need to use these options, then you can just use
@code{syncthing-device} instead of @code{syncthing-folder-device} in the
@code{devices} field of a @code{syncthing-folder} instance.
@table @asis
@item @code{device}
The @code{syncthing-device} for which this configuration applies.
@item @code{introduced-by} (default: @var{""})
The name of the device that "introduced" our device to the device
sharing this folder. This is only used when "introduced" devices are
removed by the introducer. See
@uref{https://docs.syncthing.net/users/introducer.html, Syncthing
introductions}.
@item @code{encryption-password} (default: @var{""})
The password used to encrypt data that is synchronized to untrusted
devices.
Beware: specifying this field will include this password as plain text
(not encrypted) and globally visible in @file{/gnu/store/}. If the
encryption-password is non-empty, then it will be used as a password to
encrypt file chunks as they are synchronized to untrusted devices. For
more information on syncing to devices you don't totally trust, see
Syncthing's documentation on
@uref{https://docs.syncthing.net/users/untrusted.html, Untrusted
(Encrypted) Devices}. Note that data transfer is always encrypted while
in transport ("end-to-end encryption"), regardless of this setting.
@end table
@end deftp
Here is a more complex example configuration for illustrative purposes:
@lisp
(service syncthing-service-type
(let ((laptop (syncthing-device (id "VHOD2D6-...-7XRMDEN")))
(desktop (syncthing-device (id "64SAZ37-...-FZJ5GUA")
(addresses '("tcp://example.com"))))
(bob-desktop (syncthing-device (id "KYIMEGO-...-FT77EAO"))))
(syncthing-configuration
(user "alice")
(config-file
(syncthing-config-file
(folders (list (syncthing-folder
(label "some-files")
(path "~/data")
(devices (list desktop laptop)))
(syncthing-folder
(label "critical-files")
(path "~/secrets")
(devices
(list desktop
laptop
(syncthing-folder-device
(device bob-desktop)
(encryption-password "mypassword"))))))))))))
@end lisp
Furthermore, @code{(gnu services ssh)} provides the following services.
@cindex SSH
@cindex SSH server