···
8
+
cfg = config.services.matrix-tuwunel;
9
+
defaultUser = "tuwunel";
10
+
defaultGroup = "tuwunel";
12
+
format = pkgs.formats.toml { };
13
+
configFile = format.generate "tuwunel.toml" cfg.settings;
16
+
meta.maintainers = with lib.maintainers; [
19
+
options.services.matrix-tuwunel = {
20
+
enable = lib.mkEnableOption "tuwunel";
22
+
package = lib.mkPackageOption pkgs "matrix-tuwunel" { };
24
+
user = lib.mkOption {
25
+
type = lib.types.nonEmptyStr;
27
+
The user {command}`tuwunel` is run as. If left as the default, the user will
28
+
automatically be created by the service.
30
+
example = "conduit";
31
+
default = defaultUser;
34
+
group = lib.mkOption {
35
+
type = lib.types.nonEmptyStr;
37
+
The group {command}`tuwunel` is run as. If left as the default, the group will
38
+
automatically be created by the service.
40
+
example = "conduit";
41
+
default = defaultGroup;
44
+
stateDirectory = lib.mkOption {
45
+
type = lib.types.nonEmptyStr;
46
+
default = "tuwunel";
47
+
example = "matrix-conduit";
49
+
The name of the directory under /var/lib/ where the database will be stored.
51
+
Note that `stateDirectory` cannot be changed once created because of the service's reliance on
52
+
systemd `StateDirectory`.
56
+
extraEnvironment = lib.mkOption {
57
+
type = lib.types.attrsOf lib.types.str;
58
+
description = "Extra Environment variables to pass to the tuwunel server.";
61
+
RUST_BACKTRACE = "yes";
65
+
settings = lib.mkOption {
66
+
type = lib.types.submodule {
67
+
freeformType = format.type;
69
+
global.server_name = lib.mkOption {
70
+
type = lib.types.nonEmptyStr;
71
+
example = "example.com";
72
+
description = "The server_name is the name of this server. It is used as a suffix for user and room ids.";
74
+
global.address = lib.mkOption {
75
+
type = lib.types.nullOr (lib.types.listOf lib.types.nonEmptyStr);
82
+
Addresses (IPv4 or IPv6) to listen on for connections by the reverse proxy/tls terminator.
83
+
If set to `null`, tuwunel will listen on IPv4 and IPv6 localhost.
84
+
Must be `null` if `unix_socket_path` is set.
87
+
global.port = lib.mkOption {
88
+
type = lib.types.listOf lib.types.port;
91
+
The port(s) tuwunel will be running on.
92
+
You need to set up a reverse proxy in your web server (e.g. apache or nginx),
93
+
so all requests to /_matrix on port 443 and 8448 will be forwarded to the tuwunel
94
+
instance running on this port.
97
+
global.unix_socket_path = lib.mkOption {
98
+
type = lib.types.nullOr lib.types.path;
101
+
Listen on a UNIX socket at the specified path. If listening on a UNIX socket,
102
+
listening on an address will be disabled. The `address` option must be set to
103
+
`null` (the default value). The option {option}`services.tuwunel.group` must
104
+
be set to a group your reverse proxy is part of.
107
+
global.unix_socket_perms = lib.mkOption {
108
+
type = lib.types.ints.positive;
110
+
description = "The default permissions (in octal) to create the UNIX socket with.";
112
+
global.max_request_size = lib.mkOption {
113
+
type = lib.types.ints.positive;
114
+
default = 20000000;
115
+
description = "Max request size in bytes. Don't forget to also change it in the proxy.";
117
+
global.allow_registration = lib.mkOption {
118
+
type = lib.types.bool;
121
+
Whether new users can register on this server.
123
+
Registration with token requires `registration_token` or `registration_token_file` to be set.
125
+
If set to true without a token configured, and
126
+
`yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse`
127
+
is set to true, users can freely register.
130
+
global.allow_encryption = lib.mkOption {
131
+
type = lib.types.bool;
133
+
description = "Whether new encrypted rooms can be created. Note: existing rooms will continue to work.";
135
+
global.allow_federation = lib.mkOption {
136
+
type = lib.types.bool;
139
+
Whether this server federates with other servers.
142
+
global.trusted_servers = lib.mkOption {
143
+
type = lib.types.listOf lib.types.nonEmptyStr;
144
+
default = [ "matrix.org" ];
146
+
Servers listed here will be used to gather public keys of other servers
147
+
(notary trusted key servers).
149
+
Currently, tuwunel doesn't support inbound batched key requests, so
150
+
this list should only contain other Synapse servers.
152
+
Example: `[ "matrix.org" "constellatory.net" "tchncs.de" ]`
158
+
# TOML does not allow null values, so we use null to omit those fields
159
+
apply = lib.filterAttrsRecursive (_: v: v != null);
161
+
Generates the tuwunel.toml configuration file. Refer to
162
+
<https://matrix-construct.github.io/tuwunel/configuration.html>
163
+
for details on supported values.
168
+
config = lib.mkIf cfg.enable {
171
+
assertion = !(cfg.settings ? global.unix_socket_path) || !(cfg.settings ? global.address);
173
+
In `services.matrix-tuwunel.settings.global`, `unix_socket_path` and `address` cannot be set at the
175
+
Leave one of the two options unset or explicitly set them to `null`.
179
+
assertion = cfg.user != defaultUser -> config ? users.users.${cfg.user};
180
+
message = "If `services.matrix-tuwunel.user` is changed, the configured user must already exist.";
183
+
assertion = cfg.group != defaultGroup -> config ? users.groups.${cfg.group};
184
+
message = "If `services.matrix-tuwunel.group` is changed, the configured group must already exist.";
187
+
assertion = "/var/lib/${cfg.settings.global.database_path}" != cfg.stateDirectory;
188
+
message = "The `services.matrix-tuwunel.stateDirectory` and `services.matrix-tuwunel.settings.global.database_path` options must match.";
192
+
users.users = lib.mkIf (cfg.user == defaultUser) {
195
+
home = cfg.settings.global.database_path;
196
+
isSystemUser = true;
200
+
users.groups = lib.mkIf (cfg.group == defaultGroup) {
201
+
${defaultGroup} = { };
204
+
services.matrix-tuwunel.settings.global.database_path = "/var/lib/${cfg.stateDirectory}/";
206
+
systemd.services.tuwunel = {
207
+
description = "Tuwunel Matrix Server";
208
+
documentation = [ "https://matrix-construct.github.io/tuwunel/" ];
209
+
wantedBy = [ "multi-user.target" ];
210
+
wants = [ "network-online.target" ];
211
+
after = [ "network-online.target" ];
212
+
environment = lib.mkMerge [
213
+
{ TUWUNEL_CONFIG = configFile; }
214
+
cfg.extraEnvironment
216
+
startLimitBurst = 5;
217
+
startLimitIntervalSec = 60;
219
+
DynamicUser = true;
223
+
DevicePolicy = "closed";
224
+
LockPersonality = true;
225
+
MemoryDenyWriteExecute = true;
226
+
NoNewPrivileges = true;
227
+
ProtectClock = true;
228
+
ProtectControlGroups = true;
229
+
ProtectHome = true;
230
+
ProtectHostname = true;
231
+
ProtectKernelLogs = true;
232
+
ProtectKernelModules = true;
233
+
ProtectKernelTunables = true;
234
+
ProtectProc = "invisible";
235
+
ProtectSystem = "strict";
236
+
PrivateDevices = true;
237
+
PrivateMounts = true;
239
+
PrivateUsers = true;
242
+
RestrictAddressFamilies = [
247
+
RestrictNamespaces = true;
248
+
RestrictRealtime = true;
249
+
RestrictSUIDSGID = true;
250
+
SystemCallArchitectures = "native";
251
+
SystemCallFilter = [
252
+
"@system-service @resources"
253
+
"~@clock @debug @module @mount @reboot @swap @cpu-emulation @obsolete @timer @chown @setuid @privileged @keyring @ipc"
255
+
SystemCallErrorNumber = "EPERM";
257
+
StateDirectory = cfg.stateDirectory;
258
+
StateDirectoryMode = "0700";
259
+
RuntimeDirectory = "tuwunel";
260
+
RuntimeDirectoryMode = "0750";
262
+
ExecStart = lib.getExe cfg.package;
263
+
Restart = "on-failure";