0
2
mirror of https://github.com/dali99/nixos-matrix-modules.git synced 2026-06-22 16:07:57 +02:00

Compare commits

..

31 Commits

Author SHA1 Message Date
danio 0e0fd9f6a4 Merge pull request #17 from h7x4/fix-worker-load-creds
workers: fix `LoadCredential` signing key passthrough
2026-06-22 11:54:27 +02:00
oysteikt 31e5b1ff26 workers: fix LoadCredential signing key passthrough 2026-06-22 18:50:01 +09:00
oysteikt 2afe9fe63d test/synapse-workers: init 2026-06-22 11:27:03 +02:00
oysteikt eca9ad769c synapse: remove deprecated lib.mdDoc usage 2026-06-22 11:27:03 +02:00
oysteikt d32df4d39e .gitignore: ignore multiple nix results 2026-06-22 11:27:03 +02:00
oysteikt 0761574bf1 flake.{nix,lock}: update nixpkgs from 25.11 -> 26.05 2026-06-22 11:27:03 +02:00
oysteikt e909fe8a91 synapse: wait for network-online.target 2026-06-22 11:27:03 +02:00
oysteikt f426b65172 tests/synapse: init
This commit ports a part of the integration test from nixpkgs to be used for
the matrix-synapse-next module.
2026-06-22 11:27:03 +02:00
oysteikt 8a095ef501 synapse: add some defaults for database configuration 2026-06-22 11:27:03 +02:00
oysteikt 470a01fa22 various: remove trailing whitespace 2026-06-22 11:27:03 +02:00
oysteikt 90ca1eb7a1 {synapse,workers}: pass signing_key_path through LoadCredential 2026-06-22 11:27:03 +02:00
oysteikt 5e392f3f5c {synapse,workers}: remove duplicate ReadWritePaths 2026-06-22 11:27:03 +02:00
oysteikt fd3297bd45 {synapse,workers}: use BindPaths to force stateDir and media_store_path to /var/lib 2026-06-22 11:27:03 +02:00
oysteikt b000bd44f0 nginx: add missing worker endpoints 2026-06-22 11:27:03 +02:00
oysteikt 5b9febcd84 {synapse,workers}: restart synapse processes on unexpected exit 2026-06-22 11:27:03 +02:00
oysteikt a0a6983589 workers: declare worker_log_config with default 2026-06-22 11:27:03 +02:00
oysteikt f0b1ce0a87 synapse: add withJemalloc setting, enable by default 2026-06-22 11:27:03 +02:00
oysteikt 585e268702 synapse: get rid of bash 2026-06-22 11:27:03 +02:00
oysteikt b331835543 {synapse,workers}: add systemd hardening 2026-06-22 11:27:03 +02:00
danio 82959f612f Merge pull request #10 from h7x4/additional-nixpkgs-2511-stuff
Additional fixes for 25.11
2025-12-08 18:16:53 +01:00
oysteikt 51665e27e2 tests/nginx-pipeline: move to checks, fix nix flake show 2025-12-09 01:39:12 +09:00
oysteikt 700aa1b8a6 flake.nix: bump nixpkgs target from 23.11 -> 25.11 2025-12-09 01:38:41 +09:00
oysteikt a82c7e2d94 treewide: toGNUCommandLineShell -> toCommandLineShellGNU 2025-12-09 01:34:24 +09:00
oysteikt 8493e635fa synapse-module: source kill from coreutils 2025-12-09 01:33:07 +09:00
danio 25b9f31ef1 Update MIGRATIONS.MD for version 0.8.0 changes
Added migration notes for version 0.8.0 regarding saml2 deprecation and its alternatives.
2025-12-04 11:28:15 +01:00
danio 19c690bb4f Remove 'saml2' from extras as it is broken 2025-12-01 01:10:31 +01:00
danio 099db715d1 synapse: Remove removed extra feature 2025-07-22 22:35:55 +02:00
danio da9dc0479f sliding-sync: remove 2025-01-02 23:34:05 +01:00
danio ff787d410c Add documentation for new sliding-sync setup and upgrade info 2024-09-27 06:21:37 +02:00
danio f8843835e2 sliding-sync: deprecate 2024-09-27 06:09:23 +02:00
danio f4e20d0360 Update README.MD 2024-08-29 10:32:38 +02:00
15 changed files with 578 additions and 201 deletions
+1
View File
@@ -1 +1,2 @@
result
result-*
+11
View File
@@ -2,6 +2,17 @@
This is a best effort document descibing neccecary changes you might have to do when updating
## 0.8.0
`saml2` is no longer enabled, as it depends on vulnerable dependencies and isnt really built in nixpks anymore.
If you need to authenticate with saml, you should deploy some sort of saml to openid bridge, instead.
## 0.6.1
enableSlidingSync, and setting matrix-synapse.sliding-sync.environmentFile (or any other sliding-sync setting)
is no longer needed for a sliding-sync setup. Upgrading will force relogins for all users.
## 0.5.0
* The module has been renamed from `synapse` to `default`
+2 -16
View File
@@ -1,3 +1,5 @@
For support and requests feel free to join [#nixos-matrix-modules:dodsorf.as](https://matrix.to/#/#nixos-matrix-modules:dodsorf.as), [uri](matrix:r/nixos-matrix-modules:dodsorf.as)
With matrix.YOURDOMAIN pointing at the server:
```
@@ -36,19 +38,3 @@ With matrix.YOURDOMAIN pointing at the server:
```
is ~enough to get a functional matrix-server running with some workers
## Sliding Sync (Element X)
Just add the following to your config and point `slidingsync.YOURDOMAIN` at the server
```
services.matrix-synapse-next = {
enableSlidingSync = true;
};
services.matrix-synapse.sliding-sync.environmentFile = "/some/file/containing/SYNCV3_SECRET=<some secret>";
```
If using [well-known delagation](https://matrix-org.github.io/synapse/v1.37/delegate.html) make sure `YOURDOMAIN/.well-known/matrix/client` matches
what's in `matrix.YOURDOMAIN/.well-known/matrix/client`
Generated
+4 -4
View File
@@ -2,16 +2,16 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1706098335,
"narHash": "sha256-r3dWjT8P9/Ah5m5ul4WqIWD8muj5F+/gbCdjiNVBKmU=",
"lastModified": 1781216227,
"narHash": "sha256-9mUW6gNwoN2SWc/l0fW4svPNOulXLl8ijqKyeSOGgJE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a77ab169a83a4175169d78684ddd2e54486ac651",
"rev": "a0374025a863d007d98e3297f6aa46cc3141c2f0",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-23.11",
"ref": "nixos-26.05",
"type": "indirect"
}
},
+9 -3
View File
@@ -2,7 +2,7 @@
description = "NixOS modules for matrix related services";
inputs = {
nixpkgs.url = "nixpkgs/nixos-23.11";
nixpkgs.url = "nixpkgs/nixos-26.05";
};
outputs = { self, nixpkgs }: {
@@ -12,7 +12,7 @@
lib = import ./lib.nix { lib = nixpkgs.lib; };
packages = let
checks = let
forAllSystems = f:
nixpkgs.lib.genAttrs [
"x86_64-linux"
@@ -20,11 +20,17 @@
"x86_64-darwin"
"aarch64-darwin"
] (system: f nixpkgs.legacyPackages.${system});
in forAllSystems (pkgs: {
in forAllSystems (pkgs: let
tests = import ./tests {
inherit nixpkgs pkgs;
matrix-lib = self.lib;
};
in {
inherit (tests)
nginx-pipeline-eval
synapse
synapse-workers
;
});
};
}
+1 -1
View File
@@ -6,7 +6,7 @@ rec {
firstListenerOfType = type: ls: lib.lists.findFirst (isListenerType type)
(throw "No listener with resource: ${type} configured")
ls;
# Get an attrset of the host and port from a listener
# Get an attrset of the host and port from a listener
connectionInfo = l: {
host = lib.head l.bind_addresses;
port = l.port;
+8 -2
View File
@@ -1,8 +1,14 @@
{ ... }:
{ lib, ... }:
{
imports = [
./synapse-module
./sliding-sync
# TODO: Remove after 25.05
(lib.mkRemovedOptionModule [ "services" "matrix-synapse" "sliding-sync" ] ''
`services.matrix-synapse.sliding-sync` is no longer necessary to use sliding-sync with synapse.
As synapse now includes this in itself, if you have a manually managed `.well-known/matrix/client` file
remove the proxy url from it.
'')
];
}
-117
View File
@@ -1,117 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.matrix-synapse.sliding-sync;
in
{
disabledModules = [ "services/matrix/matrix-sliding-sync.nix" ];
options.services.matrix-synapse.sliding-sync = {
enable = lib.mkEnableOption (lib.mdDoc "sliding sync");
package = lib.mkOption {
type = lib.types.package;
default = pkgs.matrix-sliding-sync;
description = "What package to use for the sliding-sync proxy.";
};
enableNginx = lib.mkEnableOption (lib.mdDoc "autogenerated nginx config");
publicBaseUrl = lib.mkOption {
type = lib.types.str;
description = "The domain where clients connect, only has an effect with enableNginx";
example = "slidingsync.matrix.org";
};
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = with lib.types; attrsOf str;
options = {
SYNCV3_SERVER = lib.mkOption {
type = lib.types.str;
description = lib.mdDoc ''
The destination homeserver to talk to not including `/_matrix/` e.g `https://matrix.example.org`.
'';
};
SYNCV3_DB = lib.mkOption {
type = lib.types.str;
default = "postgresql:///matrix-sliding-sync?host=/run/postgresql";
description = lib.mdDoc ''
The postgres connection string.
Refer to <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING>.
'';
};
SYNCV3_BINDADDR = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1:8009";
example = "[::]:8008";
description = lib.mdDoc "The interface and port to listen on.";
};
SYNCV3_LOG_LEVEL = lib.mkOption {
type = lib.types.enum [ "trace" "debug" "info" "warn" "error" "fatal" ];
default = "info";
description = lib.mdDoc "The level of verbosity for messages logged.";
};
};
};
default = { };
description = ''
Freeform environment variables passed to the sliding sync proxy.
Refer to <https://github.com/matrix-org/sliding-sync#setup> for all supported values.
'';
};
createDatabase = lib.mkOption {
type = lib.types.bool;
default = true;
description = lib.mdDoc ''
Whether to enable and configure `services.postgres` to ensure that the database user `matrix-sliding-sync`
and the database `matrix-sliding-sync` exist.
'';
};
environmentFile = lib.mkOption {
type = lib.types.str;
description = lib.mdDoc ''
Environment file as defined in {manpage}`systemd.exec(5)`.
This must contain the {env}`SYNCV3_SECRET` variable which should
be generated with {command}`openssl rand -hex 32`.
'';
};
};
config = lib.mkIf cfg.enable {
services.postgresql = lib.optionalAttrs cfg.createDatabase {
enable = true;
ensureDatabases = [ "matrix-sliding-sync" ];
ensureUsers = [ rec {
name = "matrix-sliding-sync";
ensureDBOwnership = true;
} ];
};
systemd.services.matrix-sliding-sync = {
after = lib.optional cfg.createDatabase "postgresql.service";
wantedBy = [ "multi-user.target" ];
environment = cfg.settings;
serviceConfig = {
DynamicUser = true;
EnvironmentFile = cfg.environmentFile;
ExecStart = lib.getExe cfg.package;
StateDirectory = "matrix-sliding-sync";
WorkingDirectory = "%S/matrix-sliding-sync";
};
};
services.nginx.virtualHosts.${cfg.publicBaseUrl} = lib.mkIf cfg.enableNginx {
enableACME = lib.mkDefault true;
forceSSL = true;
locations."/" = {
proxyPass = lib.replaceStrings [ "0.0.0.0" "::" ] [ "127.0.0.1" "::1" ] "http://${cfg.settings.SYNCV3_BINDADDR}";
};
};
};
}
+154 -40
View File
@@ -1,7 +1,8 @@
{ pkgs, lib, config, ... }:
let
{ pkgs, lib, options, config, ... }:
let
matrix-lib = (import ../lib.nix { inherit lib; });
opt = options.services.matrix-synapse-next;
cfg = config.services.matrix-synapse-next;
wcfg = cfg.workers;
@@ -9,17 +10,35 @@ let
cfgText = "config.services.matrix-synapse-next";
wcfgText = "config.services.matrix-synapse-next.workers";
format = pkgs.formats.yaml {};
matrix-synapse-common-config = format.generate "matrix-synapse-common-config.yaml" (cfg.settings // {
listeners = map (lib.filterAttrsRecursive (_: v: v != null)) cfg.settings.listeners;
});
usesCustomSigningKeyPath = cfg.settings.signing_key_path != (opt.settings.type.getSubOptions { }).signing_key_path.default;
format = pkgs.formats.yaml { };
matrix-synapse-common-config = lib.pipe cfg.settings [
(settings: settings // {
listeners = map (lib.filterAttrsRecursive (_: v: v != null)) cfg.settings.listeners;
media_store_path = "/var/lib/matrix-synapse/media_store";
})
(settings: settings // (lib.optionalAttrs usesCustomSigningKeyPath {
signing_key_path = "/run/credentials/matrix-synapse.service/signing_key";
}))
(let
filterRecursiveNull =
o:
if lib.isAttrs o then
lib.mapAttrs (_: v: filterRecursiveNull v) (lib.filterAttrs (_: v: v != null) o)
else if lib.isList o then
map filterRecursiveNull (lib.filter (v: v != null) o)
else
o;
in filterRecursiveNull)
(format.generate "matrix-synapse-common-config.yaml")
];
# TODO: Align better with the upstream module
wrapped = cfg.package.override {
wrapped = cfg.package.override {
inherit (cfg) plugins;
extras = [
"postgres"
"saml2"
"oidc"
"systemd"
"url-preview"
@@ -27,7 +46,6 @@ let
"jwt"
"redis"
"cache-memory"
"user-search"
];
};
@@ -72,6 +90,14 @@ in
'';
};
withJemalloc = mkOption {
type = types.bool;
default = true;
description = ''
Whether to preload jemalloc to reduce memory fragmentation and overall usage.
'';
};
dataDir = mkOption {
type = types.path;
default = "/var/lib/matrix-synapse";
@@ -109,7 +135,7 @@ in
description = "A yaml python logging config file";
};
enableSlidingSync = mkEnableOption (lib.mdDoc "automatic Sliding Sync setup at `slidingsync.<domain>`");
enableSlidingSync = mkEnableOption "automatic Sliding Sync setup at `slidingsync.<domain>`";
settings = mkOption {
type = types.submodule {
@@ -262,6 +288,30 @@ in
];
};
database.name = mkOption {
type = types.enum [ "psycopg2" ];
default = "psycopg2";
description = ''
The database engine name. Hardcoded to psycopg2, this module is not designed for use with sqlite.
'';
};
database.args.database = mkOption {
type = types.str;
default = "matrix-synapse";
description = ''
Name of the database.
'';
};
database.args.user = mkOption {
type = types.nullOr types.str;
default = "matrix-synapse";
description = ''
Username to use when connecting to postgresql.
'';
};
federation_ip_range_blacklist = mkOption {
type = types.listOf types.str;
description = ''
@@ -395,11 +445,13 @@ in
message = "Some listeners are missing either a socket path or a bind_address + port to listen on";
}) cfg.settings.listeners);
warnings = [ ] ++ lib.optional cfg.enableSlidingSync
"the option services.matrix-synapse-next.enableSlidingSync no longer has any effect (and is enabled by default)";
users.users.matrix-synapse = {
group = "matrix-synapse";
home = cfg.dataDir;
home = "/var/lib/matrix-synapse";
createHome = true;
shell = "${pkgs.bash}/bin/bash";
uid = config.ids.uids.matrix-synapse;
};
@@ -410,7 +462,8 @@ in
systemd = {
targets.matrix-synapse = {
description = "Matrix synapse parent target";
after = [ "network.target" ];
after = [ "network-online.target" ];
requires = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
};
@@ -420,51 +473,112 @@ in
after= [ "system.slice" ];
};
tmpfiles.settings."10-matrix-synapse" = {
"${cfg.dataDir}".d = lib.mkIf (cfg.dataDir != "/var/lib/matrix-synapse") {
user = "matrix-synapse";
group = "matrix-synapse";
mode = "0700";
};
"${cfg.settings.media_store_path}".d = lib.mkIf (cfg.settings.media_store_path != "/var/lib/matrix-synapse/media_store") {
user = "matrix-synapse";
group = "matrix-synapse";
mode = "0700";
};
};
services.matrix-synapse = {
description = "Synapse Matrix homeserver";
partOf = [ "matrix-synapse.target" ];
wantedBy = [ "matrix-synapse.target" ];
after = lib.mkIf (config.systemd.tmpfiles.settings."10-matrix-synapse" != { }) [
"systemd-tmpfiles-setup.service"
"systemd-tmpfiles-resetup.service"
];
preStart = let
flags = lib.cli.toGNUCommandLineShell {} {
config-path = [ matrix-synapse-common-config ] ++ cfg.extraConfigFiles;
keys-directory = cfg.dataDir;
generate-keys = true;
};
in "${cfg.package}/bin/synapse_homeserver ${flags}";
environment = lib.optionalAttrs cfg.withJemalloc {
LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so";
PYTHONMALLOC = "malloc";
};
serviceConfig = {
Type = "notify";
User = "matrix-synapse";
Group = "matrix-synapse";
Slice = "system-matrix-synapse.slice";
WorkingDirectory = cfg.dataDir;
Restart = "always";
RestartSec = 3;
WorkingDirectory = "/var/lib/matrix-synapse";
StateDirectory = "matrix-synapse";
RuntimeDirectory = "matrix-synapse";
ExecStart = let
flags = lib.cli.toGNUCommandLineShell {} {
ExecStartPre = let
flags = lib.cli.toCommandLineShellGNU {} {
config-path = [ matrix-synapse-common-config ] ++ cfg.extraConfigFiles;
keys-directory = cfg.dataDir;
keys-directory = "/var/lib/matrix-synapse";
generate-keys = true;
};
in "${cfg.package}/bin/synapse_homeserver ${flags}";
ExecStart = let
flags = lib.cli.toCommandLineShellGNU {} {
config-path = [ matrix-synapse-common-config ] ++ cfg.extraConfigFiles;
keys-directory = "/var/lib/matrix-synapse";
};
in "${wrapped}/bin/synapse_homeserver ${flags}";
ExecReload = "${pkgs.utillinux}/bin/kill -HUP $MAINPID";
Restart = "on-failure";
ExecReload = "${lib.getExe' pkgs.coreutils "kill"} -HUP $MAINPID";
AmbientCapabilities = [ "" ];
CapabilityBoundingSet = [ "" ];
LockPersonality = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
BindPaths = (lib.optionals (cfg.dataDir != "/var/lib/matrix-synapse") [
"${cfg.dataDir}:/var/lib/matrix-synapse"
]) ++ (lib.optionals (cfg.settings.media_store_path != "${cfg.dataDir}/media_store") [
"${cfg.settings.media_store_path}:/var/lib/matrix-synapse/media_store"
]);
ReadWritePaths = lib.pipe cfg.settings.listeners [
(lib.filter (listener: listener.path != null))
(map (listener: dirOf listener.path))
(lib.filter (path: path != "/run/matrix-synapse"))
lib.uniqueStrings
];
LoadCredential = lib.mkIf usesCustomSigningKeyPath [
"signing_key:${cfg.settings.signing_key_path}"
];
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindAllow = lib.catAttrs "port" cfg.settings.listeners;
SocketBindDeny = "any";
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@resources"
"~@privileged"
];
UMask = "0027";
};
};
};
services.matrix-synapse-next.settings.extra_well_known_client_content."org.matrix.msc3575.proxy" = mkIf cfg.enableSlidingSync {
url = "https://${config.services.matrix-synapse.sliding-sync.publicBaseUrl}";
};
services.matrix-synapse.sliding-sync = mkIf cfg.enableSlidingSync {
enable = true;
enableNginx = lib.mkDefault cfg.enableNginx;
publicBaseUrl = lib.mkDefault "slidingsync.${cfg.settings.server_name}";
settings = {
SYNCV3_SERVER = lib.mkDefault "https://${cfg.public_baseurl}";
SYNCV3_PROM = lib.mkIf cfg.settings.enable_metrics (lib.mkDefault "127.0.0.1:9001");
};
};
};
}
+16 -2
View File
@@ -24,6 +24,7 @@ in
~^/_matrix/client/(api/v1|r0|v3)/rooms/[^/]+/initialSync$ synapse_initial_sync;
# Federation requests
~^/_matrix/federation/v1/version$ synapse_federation;
~^/_matrix/federation/v1/event/ synapse_federation;
~^/_matrix/federation/v1/state/ synapse_federation;
~^/_matrix/federation/v1/state_ids/ synapse_federation;
@@ -35,6 +36,8 @@ in
~^/_matrix/federation/v1/make_leave/ synapse_federation;
~^/_matrix/federation/(v1|v2)/send_join/ synapse_federation;
~^/_matrix/federation/(v1|v2)/send_leave/ synapse_federation;
~^/_matrix/federation/v1/make_knock/ synapse_federation;
~^/_matrix/federation/v1/send_knock/ synapse_federation;
~^/_matrix/federation/(v1|v2)/invite/ synapse_federation;
~^/_matrix/federation/v1/event_auth/ synapse_federation;
~^/_matrix/federation/v1/timestamp_to_event/ synapse_federation;
@@ -56,17 +59,23 @@ in
~^/_matrix/client/v1/rooms/.*/hierarchy$ synapse_client_interaction;
~^/_matrix/client/(v1|unstable)/rooms/.*/relations/ synapse_client_interaction;
~^/_matrix/client/v1/rooms/.*/threads$ synapse_client_interaction;
~^/_matrix/client/unstable/org.matrix.msc2716/rooms/.*/batch_send$ synapse_client_interaction;
~^/_matrix/client/unstable/im.nheko.summary/rooms/.*/summary$ synapse_client_interaction;
~^/_matrix/client/(r0|v3|unstable)/account/3pid$ synapse_client_interaction;
~^/_matrix/client/(r0|v3|unstable)/account/whoami$ synapse_client_interaction;
~^/_matrix/client/(r0|v3|unstable)/devices$ synapse_client_interaction;
~^/_matrix/client/(r0|v3|unstable)/account/deactivate$ synapse_client_interaction;
~^/_matrix/client/(r0|v3)/delete_devices$ synapse_client_interaction;
~^/_matrix/client/(api/v1|r0|v3|unstable)/devices(/|$) synapse_client_interaction;
~^/_matrix/client/versions$ synapse_client_interaction;
~^/_matrix/client/(api/v1|r0|v3|unstable)/voip/turnServer$ synapse_client_interaction;
~^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/event/ synapse_client_interaction;
~^/_matrix/client/(api/v1|r0|v3|unstable)/joined_rooms$ synapse_client_interaction;
~^/_matrix/client/v1/rooms/.*/timestamp_to_event$ synapse_client_interaction;
~^/_matrix/client/(api/v1|r0|v3|unstable/.*)/rooms/.*/aliases synapse_client_interaction;
~^/_matrix/client/(api/v1|r0|v3|unstable)/search$ synapse_client_interaction;
~^/_matrix/client/(r0|v3|unstable)/user/.*/filter(/|$) synapse_client_interaction;
~^/_matrix/client/(api/v1|r0|v3|unstable)/directory/room/.*$ synapse_client_interaction;
~^/_matrix/client/(r0|v3|unstable)/capabilities$ synapse_client_interaction;
~^/_matrix/client/(r0|v3|unstable)/notifications$ synapse_client_interaction;
# Encryption requests
~^/_matrix/client/(r0|v3|unstable)/keys/query$ synapse_client_encryption;
@@ -74,11 +83,15 @@ in
~^/_matrix/client/(r0|v3|unstable)/keys/claim$ synapse_client_encryption;
~^/_matrix/client/(r0|v3|unstable)/room_keys/ synapse_client_encryption;
~^/_matrix/client/(r0|v3|unstable)/keys/upload/ synapse_client_encryption;
~^/_matrix/client/(api/v1|r0|v3|unstable)/keys/device_signing/upload$ synapse_client_encryption;
~^/_matrix/client/(api/v1|r0|v3|unstable)/keys/signatures/upload$ synapse_client_encryption;
# Registration/login requests
~^/_matrix/client/(api/v1|r0|v3|unstable)/login$ synapse_client_login;
~^/_matrix/client/(r0|v3|unstable)/register$ synapse_client_login;
~^/_matrix/client/(r0|v3|unstable)/register/available$ synapse_client_login;
~^/_matrix/client/v1/register/m.login.registration_token/validity$ synapse_client_login;
~^/_matrix/client/(r0|v3|unstable)/password_policy$ synapse_client_login;
# Event sending requests
~^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/redact synapse_client_transaction;
@@ -86,6 +99,7 @@ in
~^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/state/ synapse_client_transaction;
~^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/(join|invite|leave|ban|unban|kick)$ synapse_client_transaction;
~^/_matrix/client/(api/v1|r0|v3|unstable)/join/ synapse_client_transaction;
~^/_matrix/client/(api/v1|r0|v3|unstable)/knock/ synapse_client_transaction;
~^/_matrix/client/(api/v1|r0|v3|unstable)/profile/ synapse_client_transaction;
# Account data requests
+102 -14
View File
@@ -4,8 +4,8 @@
throw',
format
}:
{ pkgs, lib, config, ... }: let
{ pkgs, lib, options, config, ... }: let
opt = options.services.matrix-synapse-next;
cfg = config.services.matrix-synapse-next;
wcfg = config.services.matrix-synapse-next.workers;
@@ -13,6 +13,8 @@
cfgText = "config.services.matrix-synapse-next";
wcfgText = "config.services.matrix-synapse-next.workers";
usesCustomSigningKeyPath = cfg.settings.signing_key_path != (opt.settings.type.getSubOptions { }).signing_key_path.default;
inherit (lib) types mkOption mkEnableOption mkIf mkMerge literalExpression;
mkWorkerCountOption = workerType: mkOption {
@@ -56,7 +58,7 @@ in {
workerSettingsType = instanceCfg: types.submodule {
freeformType = format.type;
options = {
worker_app = mkOption {
type = types.enum [
@@ -74,6 +76,16 @@ in {
description = "Listener configuration for the worker, similar to the main synapse listener";
default = [ ];
};
worker_log_config = mkOption {
type = types.path;
description = ''
A yaml python logging config file as described by
https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema
'';
default = pkgs.writeText "log_config.yaml" cfg.mainLogConfig;
defaultText = "A config file generated from ${cfgText}.mainLogConfig";
};
};
};
@@ -283,7 +295,7 @@ in {
stream_writers.events =
mkIf (wcfg.eventPersisters > 0)
(lib.genList (i: "auto-event-persist${toString (i + 1)}") wcfg.eventPersisters);
(lib.genList (i: "auto-event-persist${toString (i + 1)}") wcfg.eventPersisters);
update_user_directory_from_worker =
mkIf wcfg.useUserDirectoryWorker "auto-user-dir";
@@ -360,28 +372,51 @@ in {
systemd.services = let
workerList = lib.mapAttrsToList lib.nameValuePair wcfg.instances;
workerConfig = worker:
format.generate "matrix-synapse-worker-${worker.name}-config.yaml"
(worker.value.settings // {
worker_name = worker.name;
worker_listeners =
map (lib.filterAttrsRecursive (_: v: v != null)) worker.value.settings.worker_listeners;
});
format.generate "matrix-synapse-worker-${worker.name}-config.yaml" (
worker.value.settings
//
{
worker_name = worker.name;
worker_listeners = map (lib.filterAttrsRecursive (_: v: v != null)) worker.value.settings.worker_listeners;
}
//
# NOTE: the workers cannot pick up creds from `/run/credentials/matrix-synapse.service/*`
(lib.optionalAttrs usesCustomSigningKeyPath {
signing_key_path = "/run/credentials/matrix-synapse-worker-${worker.name}.service/signing_key";
})
);
in builtins.listToAttrs (lib.flip map workerList (worker: {
name = "matrix-synapse-worker-${worker.name}";
value = {
description = "Synapse Matrix Worker";
partOf = [ "matrix-synapse.target" ];
wantedBy = [ "matrix-synapse.target" ];
after = [ "matrix-synapse.service" ];
after = [
"matrix-synapse.service"
] ++ (lib.optionals (config.systemd.tmpfiles.settings."10-matrix-synapse" != { }) [
"systemd-tmpfiles-setup.service"
"systemd-tmpfiles-resetup.service"
]);
requires = [ "matrix-synapse.service" ];
environment = lib.optionalAttrs cfg.withJemalloc {
LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so";
PYTHONMALLOC = "malloc";
};
serviceConfig = {
Type = "notify";
User = "matrix-synapse";
Group = "matrix-synapse";
Slice = "system-matrix-synapse.slice";
WorkingDirectory = cfg.dataDir;
Restart = "always";
RestartSec = 3;
WorkingDirectory = "/var/lib/matrix-synapse";
RuntimeDirectory = "matrix-synapse";
StateDirectory = "matrix-synapse";
ExecStartPre = pkgs.writers.writeBash "wait-for-synapse" ''
# From https://md.darmstadt.ccc.de/synapse-at-work
while ! systemctl is-active -q matrix-synapse.service; do
@@ -389,11 +424,64 @@ in {
done
'';
ExecStart = let
flags = lib.cli.toGNUCommandLineShell {} {
flags = lib.cli.toCommandLineShellGNU {} {
config-path = [ matrix-synapse-common-config (workerConfig worker) ] ++ cfg.extraConfigFiles;
keys-directory = cfg.dataDir;
keys-directory = "/var/lib/matrix-synapse";
};
in "${wrapped}/bin/synapse_worker ${flags}";
AmbientCapabilities = [ "" ];
CapabilityBoundingSet = [ "" ];
LockPersonality = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
BindPaths = (lib.optionals (cfg.dataDir != "/var/lib/matrix-synapse") [
"${cfg.dataDir}:/var/lib/matrix-synapse"
]) ++ (lib.optionals (cfg.settings.media_store_path != "${cfg.dataDir}/media_store") [
"${cfg.settings.media_store_path}:/var/lib/matrix-synapse/media_store"
]);
ReadWritePaths = lib.pipe cfg.settings.listeners [
(lib.filter (listener: listener.path != null))
(map (listener: dirOf listener.path))
(lib.filter (path: path != "/run/matrix-synapse"))
lib.uniqueStrings
];
LoadCredential = lib.mkIf usesCustomSigningKeyPath [
"signing_key:${cfg.settings.signing_key_path}"
];
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SocketBindAllow = lib.pipe worker.value.settings.worker_listeners [
(map (lib.filterAttrsRecursive (_: v: v != null)))
(lib.catAttrs "port")
];
SocketBindDeny = "any";
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@resources"
"~@privileged"
];
UMask = "0027";
};
};
}));
+4 -1
View File
@@ -1,4 +1,7 @@
{ nixpkgs, pkgs, matrix-lib, ... }:
{
nginx-pipeline = pkgs.callPackage ./nginx-pipeline { inherit nixpkgs matrix-lib; };
nginx-pipeline-eval = pkgs.callPackage ./nginx-pipeline { inherit nixpkgs matrix-lib; };
synapse = pkgs.testers.runNixOSTest ./synapse;
synapse-workers = pkgs.testers.runNixOSTest ./synapse-workers;
}
+1 -1
View File
@@ -5,7 +5,7 @@ let
modules = [
../../module.nix
{
system.stateVersion = "23.11";
system.stateVersion = "25.11";
boot.isContainer = true;
services.matrix-synapse-next = {
enable = true;
+52
View File
@@ -0,0 +1,52 @@
{ pkgs, ... }:
{
name = "matrix-synapse-workers";
nodes = {
server =
{
pkgs,
nodes,
...
}:
{
imports = [
../../synapse-module
];
services.postgresql = {
enable = true;
initialScript = pkgs.writeText "synapse-init.sql" ''
CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
TEMPLATE template0
LC_COLLATE = "C"
LC_CTYPE = "C";
'';
};
services.matrix-synapse-next = {
enable = true;
workers.federationSenders = 1;
workers.federationReceivers = 1;
workers.initialSyncers = 1;
workers.normalSyncers = 1;
workers.eventPersisters = 1;
workers.useUserDirectoryWorker = true;
settings = {
server_name = "example.com";
database = {
args.password = "synapse";
};
};
};
services.redis.servers."".enable = true;
};
};
testScript = ''
server.wait_for_unit("matrix-synapse.target");
'';
}
+213
View File
@@ -0,0 +1,213 @@
# Modified from https://github.com/NixOS/nixpkgs/blob/nixos-26.05/nixos/tests/matrix/synapse.nix
{ pkgs, lib, ... }:
let
mailerCerts = import /${pkgs.path}/nixos/tests/common/acme/server/snakeoil-certs.nix;
mailerDomain = mailerCerts.domain;
registrationSharedSecret = "unsecure123";
testUser = "alice";
testPassword = "alicealice";
testEmail = "alice@example.com";
in
{
name = "matrix-synapse";
nodes = {
# Since 0.33.0, matrix-synapse doesn't allow underscores in server names
server =
{
pkgs,
nodes,
config,
...
}:
let
mailserverIP = nodes.mailserver.networking.primaryIPAddress;
in
{
imports = [
../../synapse-module
];
services.matrix-synapse-next = {
enable = true;
settings = {
registration_shared_secret = registrationSharedSecret;
server_name = "example.com";
public_baseurl = "https://example.com";
database = {
args.password = "synapse";
};
redis = {
enabled = true;
host = "localhost";
port = config.services.redis.servers.matrix-synapse.port;
};
email = {
smtp_host = mailerDomain;
smtp_port = 25;
require_transport_security = true;
notif_from = "matrix <matrix@${mailerDomain}>";
app_name = "Matrix";
};
listeners = [
{
port = 8448;
bind_addresses = [
"127.0.0.1"
"::1"
];
type = "http";
x_forwarded = false;
resources = [
{
names = [
"client"
];
compress = true;
}
{
names = [
"federation"
];
compress = false;
}
];
}
];
};
};
services.postgresql = {
enable = true;
# The database name and user are configured by the following options:
# - services.matrix-synapse.database_name
# - services.matrix-synapse.database_user
#
# The values used here represent the default values of the module.
initialScript = pkgs.writeText "synapse-init.sql" ''
CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
TEMPLATE template0
LC_COLLATE = "C"
LC_CTYPE = "C";
'';
};
services.redis.servers.matrix-synapse = {
enable = true;
port = 6380;
};
networking.extraHosts = ''
${mailserverIP} ${mailerDomain}
'';
security.pki.certificateFiles = [
mailerCerts.ca.cert
];
environment.systemPackages =
let
sendTestMailStarttls = pkgs.writeScriptBin "send-testmail-starttls" ''
#!${pkgs.python3.interpreter}
import smtplib
import ssl
ctx = ssl.create_default_context()
with smtplib.SMTP('${mailerDomain}') as smtp:
smtp.ehlo()
smtp.starttls(context=ctx)
smtp.ehlo()
smtp.sendmail('matrix@${mailerDomain}', '${testEmail}', 'Subject: Test STARTTLS\n\nTest data.')
smtp.quit()
'';
obtainTokenAndRegisterEmail =
let
# adding the email through the API is quite complicated as it involves more than one step and some
# client-side calculation
insertEmailForAlice = pkgs.writeText "alice-email.sql" ''
INSERT INTO user_threepids (user_id, medium, address, validated_at, added_at)
VALUES ('${testUser}@server', 'email', '${testEmail}', '1629149927271', '1629149927270');
'';
in
pkgs.writeScriptBin "obtain-token-and-register-email" ''
#!${pkgs.runtimeShell}
set -o errexit
set -o pipefail
set -o nounset
su postgres -c "psql -d matrix-synapse -f ${insertEmailForAlice}"
curl --fail -XPOST -v 'http://localhost:8448/_matrix/client/r0/account/password/email/requestToken' --json '${builtins.toJSON {
email = testEmail;
client_secret = "foobar";
send_attempt = 1;
}}'
'';
in
[
sendTestMailStarttls
pkgs.matrix-synapse
obtainTokenAndRegisterEmail
];
};
# test mail delivery
mailserver = args: {
security.pki.certificateFiles = [
mailerCerts.ca.cert
];
networking.firewall.enable = false;
services.postfix = {
enable = true;
enableSubmission = true;
# blackhole transport
transport = "example.com discard:silently";
settings.main = {
myhostname = "${mailerDomain}";
# open relay for subnet
mynetworks_style = "subnet";
debug_peer_level = "10";
smtpd_relay_restrictions = [
"permit_mynetworks"
"reject_unauth_destination"
];
# disable obsolete protocols, something old versions of twisted are still using
smtpd_tls_protocols = "TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
smtpd_tls_mandatory_protocols = "TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
smtpd_tls_chain_files = [
"${mailerCerts.${mailerDomain}.key}"
"${mailerCerts.${mailerDomain}.cert}"
];
};
};
};
};
testScript = ''
start_all()
mailserver.wait_for_unit("postfix.service")
server.succeed("send-testmail-starttls")
server.wait_for_unit("matrix-synapse.service")
server.wait_until_succeeds(
"curl --fail -L http://localhost:8448/"
)
server.wait_until_succeeds(
"journalctl -u matrix-synapse.service | grep -q 'Connected to redis'"
)
server.require_unit_state("postgresql.target")
server.succeed("register_new_matrix_user -u ${testUser} -p ${testPassword} -a -k ${registrationSharedSecret} 'http://localhost:8448/'")
server.succeed("obtain-token-and-register-email")
'';
}