From fa1adb5a3768e6a775aa1d31a8caf53c909c7481 Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Sat, 3 Feb 2024 23:19:58 +0100 Subject: [PATCH] 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. --- .../manual/release-notes/rl-2405.section.md | 2 + nixos/modules/services/matrix/synapse.nix | 79 ++++++++++++++++--- 2 files changed, 71 insertions(+), 10 deletions(-) diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index 06c3e1949b70ab5..ac2c2d515f762d1 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -239,6 +239,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - `services.postgresql.extraPlugins` changed its type from just a list of packages to also a function that returns such a list. For example a config line like ``services.postgresql.extraPlugins = with pkgs.postgresql_11.pkgs; [ postgis ];`` is recommended to be changed to ``services.postgresql.extraPlugins = ps: with ps; [ postgis ];``; +- The Matrix homeserver [Synapse](https://element-hq.github.io/synapse/) can now, through the `path` option, bind its [listeners](#opt-services.matrix-synapse.settings.listeners) to UNIX domain sockets. + - Programs written in [Nim](https://nim-lang.org/) are built with libraries selected by lockfiles. The `nimPackages` and `nim2Packages` sets have been removed. See https://nixos.org/manual/nixpkgs/unstable#nim for more information. diff --git a/nixos/modules/services/matrix/synapse.nix b/nixos/modules/services/matrix/synapse.nix index 4c1c396eac05649..6d51a1a198803d6 100644 --- a/nixos/modules/services/matrix/synapse.nix +++ b/nixos/modules/services/matrix/synapse.nix @@ -105,6 +105,13 @@ let SYSLOG_IDENTIFIER = logName; }; }); + + toIntBase8 = str: + lib.pipe str [ + lib.stringToCharacters + (map lib.toInt) + (lib.foldl (acc: digit: acc * 8 + digit) 0) + ]; in { imports = [ @@ -195,7 +202,8 @@ in { listenerType = workerContext: types.submodule { 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,7 +211,7 @@ in { }; bind_addresses = mkOption { - type = types.listOf types.str; + type = types.nullOr (types.listOf types.str); default = [ "::1" "127.0.0.1" @@ -219,6 +227,34 @@ 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.str; + default = if 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 = toIntBase8; + }; + type = mkOption { type = types.enum [ "http" @@ -244,11 +280,17 @@ in { x_forwarded = mkOption { type = types.bool; - default = false; + default = path != null; + defaultText = literalExpression '' + path != null + ''; example = true; description = lib.mdDoc '' Use the X-Forwarded-For (XFF) header as the client IP and not the actual client IP. + + ::: {.note} + Defaults to `true`, when {option}`path` is configured. ''; }; @@ -616,8 +658,7 @@ 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; @@ -630,7 +671,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) + for use a UNIX domain socket for worker replication. See [`services.matrix-synapse.workers`](#opt-services.matrix-synapse.workers) for more details. ''; }; @@ -992,6 +1033,17 @@ in { by synapse in `services.matrix-synapse.settings.listeners` or in one of the workers! ''; } + { + assertion = lib.all + ( + listener: + listener.path != null || (listener.bind_addresses != null && listener.port != null) + ) cfg.settings.listeners; + message = '' + Listener configurations require either `bind_addresses` and `port` for TCP sockets, + or `path` for UNIX domain sockets. + ''; + } { assertion = hasWorkers -> cfg.settings.redis.enabled; message = '' @@ -1006,9 +1058,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; @@ -1029,8 +1087,7 @@ in { 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 +1143,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";