diff options
author | Martin Weinelt <hexa@darmstadt.ccc.de> | 2024-02-03 23:19:58 +0100 |
---|---|---|
committer | Martin Weinelt <hexa@darmstadt.ccc.de> | 2024-02-09 16:05:05 +0100 |
commit | 143d266f0db386af987d19e0de79128bc8669714 (patch) | |
tree | e92edb8babb273402298c0e9b5e3409f4e4abcfc /nixos/modules/services/matrix | |
parent | 2565ab7b53ae6966bd08e68203a89645961849b3 (diff) |
nixos/matrix-synapse: add UNIX domain socket listener support
Exposes two options, `path` and `mode`, to configure the location and
permissions on the socket file.
The `mode` needs to be specified as string in octal and will be converted
into a decimal integer, so it correctly passes through the YAML parser
and arrives at the `os.chmod` call in the Twisted codebase. What a fun
detour.
Adds an assertion, that either `path` or `bind_addresses` and `port` are
configured on every listener.
Migrates the default replication listener of the main instance to a UNIX
domain socket, because it is more efficient.
Introduces the `enableRegistrationScript` option, to gracefully disable
the user registration script, when the client listener listens on a UNIX
domain socket, which is something the script does not support.
Diffstat (limited to 'nixos/modules/services/matrix')
-rw-r--r-- | nixos/modules/services/matrix/synapse.md | 5 | ||||
-rw-r--r-- | nixos/modules/services/matrix/synapse.nix | 156 |
2 files changed, 140 insertions, 21 deletions
diff --git a/nixos/modules/services/matrix/synapse.md b/nixos/modules/services/matrix/synapse.md index f270be8c8d78..9c9c025fc5f5 100644 --- a/nixos/modules/services/matrix/synapse.md +++ b/nixos/modules/services/matrix/synapse.md @@ -126,8 +126,9 @@ then enable `services.matrix-synapse.settings.enable_registration = true;`. Otherwise, or you can generate a registration secret with {command}`pwgen -s 64 1` and set it with [](#opt-services.matrix-synapse.settings.registration_shared_secret). -To create a new user or admin, run the following after you have set the secret -and have rebuilt NixOS: +To create a new user or admin from the terminal your client listener +must be configured to use TCP sockets. Then you can run the following +after you have set the secret and have rebuilt NixOS: ```ShellSession $ nix-shell -p matrix-synapse $ register_new_matrix_user -k your-registration-shared-secret http://localhost:8008 diff --git a/nixos/modules/services/matrix/synapse.nix b/nixos/modules/services/matrix/synapse.nix index 4c1c396eac05..a6304d353387 100644 --- a/nixos/modules/services/matrix/synapse.nix +++ b/nixos/modules/services/matrix/synapse.nix @@ -105,6 +105,19 @@ let SYSLOG_IDENTIFIER = logName; }; }); + + toIntBase8 = str: + lib.pipe str [ + lib.stringToCharacters + (map lib.toInt) + (lib.foldl (acc: digit: acc * 8 + digit) 0) + ]; + + toDecimalFilePermission = value: + if value == null then + null + else + toIntBase8 value; in { imports = [ @@ -192,10 +205,11 @@ in { ]; options = let - listenerType = workerContext: types.submodule { + listenerType = workerContext: types.submodule ({ config, ... }: { options = { port = mkOption { - type = types.port; + type = types.nullOr types.port; + default = null; example = 8448; description = lib.mdDoc '' The port to listen for HTTP(S) requests on. @@ -203,11 +217,20 @@ in { }; bind_addresses = mkOption { - type = types.listOf types.str; - default = [ + type = types.nullOr (types.listOf types.str); + default = if config.path != null then null else [ "::1" "127.0.0.1" ]; + defaultText = literalExpression '' + if path != null then + null + else + [ + "::1" + "127.0.0.1" + ] + ''; example = literalExpression '' [ "::" @@ -219,6 +242,35 @@ in { ''; }; + path = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Unix domain socket path to bind this listener to. + + ::: {.note} + This option is incompatible with {option}`bind_addresses`, {option}`port`, {option}`tls` + and also does not support the `metrics` and `manhole` listener {option}`type`. + ::: + ''; + }; + + mode = mkOption { + type = types.nullOr (types.strMatching "^[0,2-7]{3,4}$"); + default = if config.path != null then "660" else null; + defaultText = literalExpression '' + if path != null then + "660" + else + null + ''; + example = "660"; + description = '' + File permissions on the UNIX domain socket. + ''; + apply = toDecimalFilePermission; + }; + type = mkOption { type = types.enum [ "http" @@ -234,17 +286,30 @@ in { }; tls = mkOption { - type = types.bool; - default = !workerContext; + type = types.nullOr types.bool; + default = if config.path != null then + null + else + !workerContext; + defaultText = '' + Enabled for the main instance listener, unless it is configured with a UNIX domain socket path. + ''; example = false; description = lib.mdDoc '' Whether to enable TLS on the listener socket. + + ::: {.note} + This option will be ignored for UNIX domain sockets. + ::: ''; }; x_forwarded = mkOption { type = types.bool; - default = false; + default = config.path != null; + defaultText = '' + Enabled if the listener is configured with a UNIX domain socket path + ''; example = true; description = lib.mdDoc '' Use the X-Forwarded-For (XFF) header as the client IP and not the @@ -291,11 +356,28 @@ in { ''; }; }; - }; + }); in { services.matrix-synapse = { enable = mkEnableOption (lib.mdDoc "matrix.org synapse"); + enableRegistrationScript = mkOption { + type = types.bool; + default = clientListener.bind_addresses != []; + example = false; + defaultText = '' + Enabled if the client listener uses TCP sockets + ''; + description = '' + Whether to install the `register_new_matrix_user` script, that + allows account creation on the terminal. + + ::: {.note} + This script does not work when the client listener uses UNIX domain sockets + ::: + ''; + }; + serviceUnit = lib.mkOption { type = lib.types.str; readOnly = true; @@ -616,11 +698,8 @@ in { compress = false; }]; }] ++ lib.optional hasWorkers { - port = 9093; - bind_addresses = [ "127.0.0.1" ]; + path = "/run/matrix-synapse/main_replication.sock"; type = "http"; - tls = false; - x_forwarded = false; resources = [{ names = [ "replication" ]; compress = false; @@ -630,7 +709,7 @@ in { List of ports that Synapse should listen on, their purpose and their configuration. By default, synapse will be configured for client and federation traffic on port 8008, and - for worker replication traffic on port 9093. See [`services.matrix-synapse.workers`](#opt-services.matrix-synapse.workers) + use a UNIX domain socket for worker replication. See [`services.matrix-synapse.workers`](#opt-services.matrix-synapse.workers) for more details. ''; }; @@ -1006,9 +1085,15 @@ in { listener = lib.findFirst ( listener: - listener.port == main.port + ( + lib.hasAttr "port" main && listener.port or null == main.port + || lib.hasAttr "path" main && listener.path or null == main.path + ) && listenerSupportsResource "replication" listener - && (lib.any (bind: bind == main.host || bind == "0.0.0.0" || bind == "::") listener.bind_addresses) + && ( + lib.hasAttr "host" main && lib.any (bind: bind == main.host || bind == "0.0.0.0" || bind == "::") listener.bind_addresses + || lib.hasAttr "path" main + ) ) null cfg.settings.listeners; @@ -1022,15 +1107,44 @@ in { This is done by default unless you manually configure either of those settings. ''; } - ]; + { + assertion = cfg.enableRegistrationScript -> clientListener.path == null; + message = '' + The client listener on matrix-synapse is configured to use UNIX domain sockets. + This configuration is incompatible with the `register_new_matrix_user` script. + + Disable `services.mastrix-synapse.enableRegistrationScript` to continue. + ''; + } + ] + ++ (map (listener: { + assertion = (listener.path == null) != (listener.bind_addresses == null); + message = '' + Listeners require either a UNIX domain socket `path` or `bind_addresses` for a TCP socket. + ''; + }) cfg.settings.listeners) + ++ (map (listener: { + assertion = listener.path != null -> (listener.bind_addresses == null && listener.port == null && listener.tls == null); + message = let + formatKeyValue = key: value: lib.optionalString (value != null) " - ${key}=${toString value}\n"; + in '' + Listener configured with UNIX domain socket (${toString listener.path}) ignores the following options: + ${formatKeyValue "bind_addresses" listener.bind_addresses}${formatKeyValue "port" listener.port}${formatKeyValue "tls" listener.tls} + ''; + }) cfg.settings.listeners) + ++ (map (listener: { + assertion = listener.path == null || listener.type == "http"; + message = '' + Listener configured with UNIX domain socket (${toString listener.path}) only supports the "http" listener type. + ''; + }) cfg.settings.listeners); services.matrix-synapse.settings.redis = lib.mkIf cfg.configureRedisLocally { enabled = true; path = config.services.redis.servers.matrix-synapse.unixSocket; }; services.matrix-synapse.settings.instance_map.main = lib.mkIf hasWorkers (lib.mkDefault { - host = "127.0.0.1"; - port = 9093; + path = "/run/matrix-synapse/main_replication.sock"; }); services.matrix-synapse.serviceUnit = if hasWorkers then "matrix-synapse.target" else "matrix-synapse.service"; @@ -1086,6 +1200,8 @@ in { User = "matrix-synapse"; Group = "matrix-synapse"; WorkingDirectory = cfg.dataDir; + RuntimeDirectory = "matrix-synapse"; + RuntimeDirectoryPreserve = true; ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID"; Restart = "on-failure"; UMask = "0077"; @@ -1178,7 +1294,9 @@ in { user = "matrix-synapse"; }; - environment.systemPackages = [ registerNewMatrixUser ]; + environment.systemPackages = lib.optionals cfg.enableRegistrationScript [ + registerNewMatrixUser + ]; }; meta = { |