summary refs log tree commit diff
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2024-09-05 22:49:11 +0200
committerRory& <root@rory.gay>2024-09-05 22:49:11 +0200
commited39a6bf2da6ad1790895a1e824e74186aefc4bd (patch)
tree15799c872c7c48dbc1dacfb17e842e04ff33a1f8
parentLess synapse workers, add EDU writers (diff)
downloadRory-Open-Architecture-ed39a6bf2da6ad1790895a1e824e74186aefc4bd.tar.xz
Some synapse work, expose nheko-git and mtxclient-git packages
-rw-r--r--flake.lock96
-rwxr-xr-xflake.nix24
-rwxr-xr-xhost/Rory-nginx/services/matrix/synapse/synapse-main.nix2
-rw-r--r--host/Rory-nginx/services/matrix/synapse/workers/stream-writers/account_data-stream-writer.nix118
-rw-r--r--host/Rory-nginx/services/matrix/synapse/workers/stream-writers/presence-stream-writer.nix5
-rw-r--r--host/Rory-nginx/services/matrix/synapse/workers/stream-writers/push_rules-stream-writer.nix118
-rw-r--r--host/Rory-nginx/services/matrix/synapse/workers/stream-writers/receipts-stream-writer.nix118
-rw-r--r--host/Rory-nginx/services/matrix/synapse/workers/stream-writers/shared-stream-writer.nix123
-rw-r--r--host/Rory-nginx/services/matrix/synapse/workers/stream-writers/to_device-stream-writer.nix118
-rw-r--r--host/Rory-nginx/services/matrix/synapse/workers/stream-writers/typing-stream-writer.nix118
-rw-r--r--modules/monitoring/synapse.nix2
11 files changed, 802 insertions, 40 deletions
diff --git a/flake.lock b/flake.lock
index d86d743..ca10eda 100644
--- a/flake.lock
+++ b/flake.lock
@@ -27,7 +27,7 @@
       "inputs": {
         "crane": "crane_3",
         "flake-compat": "flake-compat_3",
-        "flake-utils": "flake-utils_3",
+        "flake-utils": "flake-utils_4",
         "nixpkgs": "nixpkgs_3",
         "nixpkgs-stable": "nixpkgs-stable_2"
       },
@@ -78,11 +78,11 @@
         "nixpkgs": "nixpkgs_2"
       },
       "locked": {
-        "lastModified": 1724351785,
-        "narHash": "sha256-LyW+qD+k32iTzv9rqauasykzzSwNs8ryHzE2ISV7Bwc=",
+        "lastModified": 1724842781,
+        "narHash": "sha256-HRF4BHnVBlosE6ksyfPPgK3OIATD6LV79CK0rpX9MMU=",
         "owner": "famedly",
         "repo": "conduit",
-        "rev": "a9c386728767ac9295ba6c362a68364f0a322fbd",
+        "rev": "2bab8869d08765a7824b9d9dd937050dddbae4f1",
         "type": "gitlab"
       },
       "original": {
@@ -340,6 +340,24 @@
       }
     },
     "flake-utils_3": {
+      "inputs": {
+        "systems": "systems_2"
+      },
+      "locked": {
+        "lastModified": 1710146030,
+        "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "flake-utils_4": {
       "locked": {
         "lastModified": 1667395993,
         "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
@@ -354,9 +372,9 @@
         "type": "github"
       }
     },
-    "flake-utils_4": {
+    "flake-utils_5": {
       "inputs": {
-        "systems": "systems_2"
+        "systems": "systems_3"
       },
       "locked": {
         "lastModified": 1710146030,
@@ -373,9 +391,9 @@
         "type": "github"
       }
     },
-    "flake-utils_5": {
+    "flake-utils_6": {
       "inputs": {
-        "systems": "systems_3"
+        "systems": "systems_4"
       },
       "locked": {
         "lastModified": 1710146030,
@@ -397,18 +415,18 @@
         "crane": "crane_4",
         "fenix": "fenix_2",
         "flake-compat": "flake-compat_4",
-        "flake-utils": "flake-utils_4",
+        "flake-utils": "flake-utils_5",
         "nix-filter": "nix-filter_2",
         "nixpkgs": "nixpkgs_4",
         "rust-manifest": "rust-manifest"
       },
       "locked": {
         "host": "gitlab.computer.surgery",
-        "lastModified": 1724527899,
-        "narHash": "sha256-aLCrE4J9BTSoqWmiLQqQngt1ZNgsDZ2bOZgPRUbV2L4=",
+        "lastModified": 1725218530,
+        "narHash": "sha256-mCBFFaOPNBnWXHugjD63qMvb2AruqJMgvSNZWY3yatY=",
         "owner": "matrix",
         "repo": "grapevine-fork",
-        "rev": "14afa1357e199e542835fde621e99052e7d12f2b",
+        "rev": "be14f5bddcf7ac7b2ab97f353efd61ae56704ab2",
         "type": "gitlab"
       },
       "original": {
@@ -423,11 +441,11 @@
         "nixpkgs": "nixpkgs_5"
       },
       "locked": {
-        "lastModified": 1724435763,
-        "narHash": "sha256-UNky3lJNGQtUEXT2OY8gMxejakSWPTfWKvpFkpFlAfM=",
+        "lastModified": 1725180166,
+        "narHash": "sha256-fzssXuGR/mCeGbzM1ExaTqDz7QDGta3WA4jJsZyRruo=",
         "owner": "nix-community",
         "repo": "home-manager",
-        "rev": "c2cd2a52e02f1dfa1c88f95abeb89298d46023be",
+        "rev": "471e3eb0a114265bcd62d11d58ba8d3421ee68eb",
         "type": "github"
       },
       "original": {
@@ -505,15 +523,15 @@
     "nixos-wsl": {
       "inputs": {
         "flake-compat": "flake-compat_5",
-        "flake-utils": "flake-utils_5",
+        "flake-utils": "flake-utils_6",
         "nixpkgs": "nixpkgs_6"
       },
       "locked": {
-        "lastModified": 1724065442,
-        "narHash": "sha256-8ZUoyeO7Q70bLuijVYvToBSkApw9kfc5hMykTGxB64I=",
+        "lastModified": 1725358307,
+        "narHash": "sha256-su/Nzp2X8JlaD9wPYQGXeTilaVa5H06X7A3kqCLJNuo=",
         "owner": "nix-community",
         "repo": "NixOS-WSL",
-        "rev": "0bec2bfb8a2d4dd16e5b012982ca95e57d50e6a2",
+        "rev": "8a89995f745b1a9029d654c391a0f62ca03f7fe7",
         "type": "github"
       },
       "original": {
@@ -572,11 +590,11 @@
     },
     "nixpkgs-master": {
       "locked": {
-        "lastModified": 1724591773,
-        "narHash": "sha256-3G7MkSEWUIigBmpd5djDtfZfx7SfPj+crUw7gdrgO3k=",
+        "lastModified": 1725492194,
+        "narHash": "sha256-LMaAYIBEqzhsinhFGlkWnNxtSsBYkSGbiBBiWoGo7xE=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "9e2335ac963ae6863194f516b57b01febd499e84",
+        "rev": "8802725063e41bf09f049017fcf8d358b6e3ba11",
         "type": "github"
       },
       "original": {
@@ -700,11 +718,11 @@
     },
     "nixpkgs_6": {
       "locked": {
-        "lastModified": 1723688146,
-        "narHash": "sha256-sqLwJcHYeWLOeP/XoLwAtYjr01TISlkOfz+NG82pbdg=",
+        "lastModified": 1725001927,
+        "narHash": "sha256-eV+63gK0Mp7ygCR0Oy4yIYSNcum2VQwnZamHxYTNi+M=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "c3d4ac725177c030b1e289015989da2ad9d56af0",
+        "rev": "6e99f2a27d600612004fbd2c3282d614bfee6421",
         "type": "github"
       },
       "original": {
@@ -716,11 +734,11 @@
     },
     "nixpkgs_7": {
       "locked": {
-        "lastModified": 1724224976,
-        "narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=",
+        "lastModified": 1725103162,
+        "narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "c374d94f1536013ca8e92341b540eba4c22f9c62",
+        "rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b",
         "type": "github"
       },
       "original": {
@@ -750,6 +768,7 @@
       "inputs": {
         "botcore-v4": "botcore-v4",
         "conduit": "conduit",
+        "flake-utils": "flake-utils_3",
         "grapevine": "grapevine",
         "home-manager": "home-manager",
         "mtxclientSrc": "mtxclientSrc",
@@ -814,11 +833,11 @@
         "nixpkgs-stable": "nixpkgs-stable_3"
       },
       "locked": {
-        "lastModified": 1723501126,
-        "narHash": "sha256-N9IcHgj/p1+2Pvk8P4Zc1bfrMwld5PcosVA0nL6IGdE=",
+        "lastModified": 1725201042,
+        "narHash": "sha256-lj5pxOwidP0W//E7IvyhbhXrnEUW99I07+QpERnzTS4=",
         "owner": "Mic92",
         "repo": "sops-nix",
-        "rev": "be0eec2d27563590194a9206f551a6f73d52fa34",
+        "rev": "5db5921e40ae382d6716dce591ea23b0a39d96f7",
         "type": "github"
       },
       "original": {
@@ -871,6 +890,21 @@
         "repo": "default",
         "type": "github"
       }
+    },
+    "systems_4": {
+      "locked": {
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
     }
   },
   "root": "root",
diff --git a/flake.nix b/flake.nix
index bcef2ce..6b9576a 100755
--- a/flake.nix
+++ b/flake.nix
@@ -22,6 +22,7 @@
     # Base modules
     home-manager.url = "github:nix-community/home-manager/master";
     sops-nix.url = "github:Mic92/sops-nix";
+    flake-utils.url = "github:numtide/flake-utils";
 
     # Packages
     grapevine.url = "gitlab:matrix/grapevine-fork?host=gitlab.computer.surgery"; # &ref=benjamin/debug-emma-kde-room";
@@ -47,7 +48,9 @@
   };
 
   outputs =
-    inputs: with inputs; {
+    inputs:
+    with inputs;
+    {
       nixosConfigurations = {
         #NIXPKGS FORK
         Rory-nginx = nixpkgs.lib.nixosSystem {
@@ -199,5 +202,22 @@
           };
         };
       };
-    };
+    }
+    // flake-utils.lib.eachSystem flake-utils.lib.allSystems (
+      system:
+      let
+        pkgs = import nixpkgs { inherit system; };
+      in
+      {
+        packages.nheko-git = (
+          pkgs.callPackage ./modules/packages/nheko-git.nix {
+            inherit nhekoSrc;
+            inherit mtxclientSrc;
+            voipSupport = false;
+          }
+        );
+
+        packages.mtxclient-git = (pkgs.callPackage ./modules/packages/mtxclient-git.nix { inherit mtxclientSrc; });
+      }
+    );
 }
diff --git a/host/Rory-nginx/services/matrix/synapse/synapse-main.nix b/host/Rory-nginx/services/matrix/synapse/synapse-main.nix
index e8f24d5..9c12e75 100755
--- a/host/Rory-nginx/services/matrix/synapse/synapse-main.nix
+++ b/host/Rory-nginx/services/matrix/synapse/synapse-main.nix
@@ -12,7 +12,7 @@
     nginxVirtualHostName = "matrix.rory.gay";
     enableWorkers = true;
 
-    federationSenders = 8; #8
+    federationSenders = 8; #16
     pushers = 1;
     mediaRepoWorkers = 2; #4
     clientReaders = 2; #4
diff --git a/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/account_data-stream-writer.nix b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/account_data-stream-writer.nix
new file mode 100644
index 0000000..200e7c9
--- /dev/null
+++ b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/account_data-stream-writer.nix
@@ -0,0 +1,118 @@
+{ config, lib, ... }:
+
+let
+  cfg = config.services.matrix-synapse;
+  dbGroup = "medium";
+  streamWriterType = "account_data";
+  workers = lib.range 0 (cfg.accountDataStreamWriters - 1);
+  workerName = "account_data_stream_writer";
+  workerRoutes = {
+    client = [ ];
+    federation = [ ];
+    media = [ ];
+  };
+in
+let
+  enabledResources =
+    lib.optionals (lib.length workerRoutes.client > 0) [ "client" ]
+    ++ lib.optionals (lib.length workerRoutes.federation > 0) [ "federation" ]
+    ++ lib.optionals (lib.length workerRoutes.media > 0) [ "media" ];
+in
+{
+  config = lib.mkIf (cfg.accountDataStreamWriters > 0) {
+    monitoring.synapse.workerNames = lib.map (index: "${workerName}-${toString index}") workers;
+    services.matrix-synapse = {
+      settings = {
+        instance_map = lib.listToAttrs (
+          lib.map (index: {
+            name = "${workerName}-${toString index}";
+            value = {
+              path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+            };
+          }) workers
+        );
+
+        stream_writers.${streamWriterType} = lib.map (index: "${workerName}-${toString index}") workers;
+      };
+
+      workers = lib.listToAttrs (
+        lib.map (index: {
+          name = "${workerName}-${toString index}";
+          value = {
+            worker_app = "synapse.app.generic_worker";
+            worker_listeners =
+              [
+                {
+                  type = "http";
+                  path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+                  resources = [
+                    {
+                      names = [ "replication" ];
+                      compress = false;
+                    }
+                  ];
+                }
+              ]
+              ++ lib.map (type: {
+                type = "http";
+                path = "/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                mode = "666";
+                resources = [
+                  {
+                    names = [ type ];
+                    compress = false;
+                  }
+                ];
+              }) enabledResources;
+            database = (
+              import ../../db.nix {
+                inherit dbGroup;
+                workerName = "${workerName}-${toString index}";
+              }
+            );
+          };
+        }) workers
+      );
+    };
+
+    services.nginx = {
+      upstreams = lib.listToAttrs (
+        lib.map (type: {
+          name = "${workerName}-${type}";
+          value = {
+            extraConfig = ''
+              keepalive 32;
+              least_conn;
+            '';
+            servers = lib.listToAttrs (
+              lib.map (index: {
+                name = "unix:/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                value = {
+                  max_fails = 0;
+                };
+              }) workers
+            );
+          };
+        }) enabledResources
+      );
+
+      virtualHosts."${cfg.nginxVirtualHostName}".locations = lib.listToAttrs (
+        lib.flatten (
+          lib.forEach enabledResources (
+            type:
+            lib.map (route: {
+              name = route;
+              value = {
+                proxyPass = "http://${workerName}-${type}";
+                extraConfig = ''
+                  proxy_http_version 1.1;
+                  proxy_set_header Connection "";
+                '';
+              };
+            }) workerRoutes.${type}
+          )
+        )
+      );
+    };
+  };
+}
diff --git a/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/presence-stream-writer.nix b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/presence-stream-writer.nix
index e906b28..84da90d 100644
--- a/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/presence-stream-writer.nix
+++ b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/presence-stream-writer.nix
@@ -33,11 +33,6 @@ in
         );
 
         stream_writers.${streamWriterType} = lib.map (index: "${workerName}-${toString index}") workers;
-        stream_writers.typing = lib.map (index: "${workerName}-${toString index}") workers;
-        stream_writers.to_device = lib.map (index: "${workerName}-${toString index}") workers;
-        stream_writers.account_data = lib.map (index: "${workerName}-${toString index}") workers;
-        stream_writers.receipts = lib.map (index: "${workerName}-${toString index}") workers;
-        stream_writers.push_rules = lib.map (index: "${workerName}-${toString index}") workers;
       };
 
       workers = lib.listToAttrs (
diff --git a/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/push_rules-stream-writer.nix b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/push_rules-stream-writer.nix
new file mode 100644
index 0000000..f4a6acc
--- /dev/null
+++ b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/push_rules-stream-writer.nix
@@ -0,0 +1,118 @@
+{ config, lib, ... }:
+
+let
+  cfg = config.services.matrix-synapse;
+  dbGroup = "medium";
+  streamWriterType = "push_rules";
+  workers = lib.range 0 (cfg.pushRuleStreamWriters - 1);
+  workerName = "push_rule_stream_writer";
+  workerRoutes = {
+    client = [ ];
+    federation = [ ];
+    media = [ ];
+  };
+in
+let
+  enabledResources =
+    lib.optionals (lib.length workerRoutes.client > 0) [ "client" ]
+    ++ lib.optionals (lib.length workerRoutes.federation > 0) [ "federation" ]
+    ++ lib.optionals (lib.length workerRoutes.media > 0) [ "media" ];
+in
+{
+  config = lib.mkIf (cfg.pushRuleStreamWriters > 0) {
+    monitoring.synapse.workerNames = lib.map (index: "${workerName}-${toString index}") workers;
+    services.matrix-synapse = {
+      settings = {
+        instance_map = lib.listToAttrs (
+          lib.map (index: {
+            name = "${workerName}-${toString index}";
+            value = {
+              path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+            };
+          }) workers
+        );
+
+        stream_writers.${streamWriterType} = lib.map (index: "${workerName}-${toString index}") workers;
+      };
+
+      workers = lib.listToAttrs (
+        lib.map (index: {
+          name = "${workerName}-${toString index}";
+          value = {
+            worker_app = "synapse.app.generic_worker";
+            worker_listeners =
+              [
+                {
+                  type = "http";
+                  path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+                  resources = [
+                    {
+                      names = [ "replication" ];
+                      compress = false;
+                    }
+                  ];
+                }
+              ]
+              ++ lib.map (type: {
+                type = "http";
+                path = "/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                mode = "666";
+                resources = [
+                  {
+                    names = [ type ];
+                    compress = false;
+                  }
+                ];
+              }) enabledResources;
+            database = (
+              import ../../db.nix {
+                inherit dbGroup;
+                workerName = "${workerName}-${toString index}";
+              }
+            );
+          };
+        }) workers
+      );
+    };
+
+    services.nginx = {
+      upstreams = lib.listToAttrs (
+        lib.map (type: {
+          name = "${workerName}-${type}";
+          value = {
+            extraConfig = ''
+              keepalive 32;
+              least_conn;
+            '';
+            servers = lib.listToAttrs (
+              lib.map (index: {
+                name = "unix:/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                value = {
+                  max_fails = 0;
+                };
+              }) workers
+            );
+          };
+        }) enabledResources
+      );
+
+      virtualHosts."${cfg.nginxVirtualHostName}".locations = lib.listToAttrs (
+        lib.flatten (
+          lib.forEach enabledResources (
+            type:
+            lib.map (route: {
+              name = route;
+              value = {
+                proxyPass = "http://${workerName}-${type}";
+                extraConfig = ''
+                  proxy_http_version 1.1;
+                  proxy_set_header Connection "";
+                '';
+              };
+            }) workerRoutes.${type}
+          )
+        )
+      );
+    };
+  };
+}
diff --git a/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/receipts-stream-writer.nix b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/receipts-stream-writer.nix
new file mode 100644
index 0000000..91583d9
--- /dev/null
+++ b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/receipts-stream-writer.nix
@@ -0,0 +1,118 @@
+{ config, lib, ... }:
+
+let
+  cfg = config.services.matrix-synapse;
+  dbGroup = "medium";
+  streamWriterType = "receipts";
+  workers = lib.range 0 (cfg.receiptStreamWriters - 1);
+  workerName = "receipts_stream_writer";
+  workerRoutes = {
+    client = [ ];
+    federation = [ ];
+    media = [ ];
+  };
+in
+let
+  enabledResources =
+    lib.optionals (lib.length workerRoutes.client > 0) [ "client" ]
+    ++ lib.optionals (lib.length workerRoutes.federation > 0) [ "federation" ]
+    ++ lib.optionals (lib.length workerRoutes.media > 0) [ "media" ];
+in
+{
+  config = lib.mkIf (cfg.receiptStreamWriters > 0) {
+    monitoring.synapse.workerNames = lib.map (index: "${workerName}-${toString index}") workers;
+    services.matrix-synapse = {
+      settings = {
+        instance_map = lib.listToAttrs (
+          lib.map (index: {
+            name = "${workerName}-${toString index}";
+            value = {
+              path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+            };
+          }) workers
+        );
+
+        stream_writers.${streamWriterType} = lib.map (index: "${workerName}-${toString index}") workers;
+      };
+
+      workers = lib.listToAttrs (
+        lib.map (index: {
+          name = "${workerName}-${toString index}";
+          value = {
+            worker_app = "synapse.app.generic_worker";
+            worker_listeners =
+              [
+                {
+                  type = "http";
+                  path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+                  resources = [
+                    {
+                      names = [ "replication" ];
+                      compress = false;
+                    }
+                  ];
+                }
+              ]
+              ++ lib.map (type: {
+                type = "http";
+                path = "/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                mode = "666";
+                resources = [
+                  {
+                    names = [ type ];
+                    compress = false;
+                  }
+                ];
+              }) enabledResources;
+            database = (
+              import ../../db.nix {
+                inherit dbGroup;
+                workerName = "${workerName}-${toString index}";
+              }
+            );
+          };
+        }) workers
+      );
+    };
+
+    services.nginx = {
+      upstreams = lib.listToAttrs (
+        lib.map (type: {
+          name = "${workerName}-${type}";
+          value = {
+            extraConfig = ''
+              keepalive 32;
+              least_conn;
+            '';
+            servers = lib.listToAttrs (
+              lib.map (index: {
+                name = "unix:/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                value = {
+                  max_fails = 0;
+                };
+              }) workers
+            );
+          };
+        }) enabledResources
+      );
+
+      virtualHosts."${cfg.nginxVirtualHostName}".locations = lib.listToAttrs (
+        lib.flatten (
+          lib.forEach enabledResources (
+            type:
+            lib.map (route: {
+              name = route;
+              value = {
+                proxyPass = "http://${workerName}-${type}";
+                extraConfig = ''
+                  proxy_http_version 1.1;
+                  proxy_set_header Connection "";
+                '';
+              };
+            }) workerRoutes.${type}
+          )
+        )
+      );
+    };
+  };
+}
diff --git a/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/shared-stream-writer.nix b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/shared-stream-writer.nix
new file mode 100644
index 0000000..3da4276
--- /dev/null
+++ b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/shared-stream-writer.nix
@@ -0,0 +1,123 @@
+{ config, lib, ... }:
+
+let
+  cfg = config.services.matrix-synapse;
+  dbGroup = "medium";
+  streamWriterType = "shared"; # unused, from template
+  workers = lib.range 0 (cfg.presenceStreamWriters - 1);
+  workerName = "shared_stream_writer";
+  workerRoutes = {
+    client = [ ];
+    federation = [ ];
+    media = [ ];
+  };
+in
+let
+  enabledResources =
+    lib.optionals (lib.length workerRoutes.client > 0) [ "client" ]
+    ++ lib.optionals (lib.length workerRoutes.federation > 0) [ "federation" ]
+    ++ lib.optionals (lib.length workerRoutes.media > 0) [ "media" ];
+in
+{
+  config = lib.mkIf (cfg.presenceStreamWriters > 0) {
+    monitoring.synapse.workerNames = lib.map (index: "${workerName}-${toString index}") workers;
+    services.matrix-synapse = {
+      settings = {
+        instance_map = lib.listToAttrs (
+          lib.map (index: {
+            name = "${workerName}-${toString index}";
+            value = {
+              path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+            };
+          }) workers
+        );
+
+        stream_writers.account_data = lib.map (index: "${workerName}-${toString index}") workers;
+        stream_writers.events = lib.map (index: "${workerName}-${toString index}") workers;
+        stream_writers.typing = lib.map (index: "${workerName}-${toString index}") workers;
+        stream_writers.to_device = lib.map (index: "${workerName}-${toString index}") workers;
+        stream_writers.receipts = lib.map (index: "${workerName}-${toString index}") workers;
+        stream_writers.push_rules = lib.map (index: "${workerName}-${toString index}") workers;
+      };
+
+      workers = lib.listToAttrs (
+        lib.map (index: {
+          name = "${workerName}-${toString index}";
+          value = {
+            worker_app = "synapse.app.generic_worker";
+            worker_listeners =
+              [
+                {
+                  type = "http";
+                  path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+                  resources = [
+                    {
+                      names = [ "replication" ];
+                      compress = false;
+                    }
+                  ];
+                }
+              ]
+              ++ lib.map (type: {
+                type = "http";
+                path = "/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                mode = "666";
+                resources = [
+                  {
+                    names = [ type ];
+                    compress = false;
+                  }
+                ];
+              }) enabledResources;
+            database = (
+              import ../../db.nix {
+                inherit dbGroup;
+                workerName = "${workerName}-${toString index}";
+              }
+            );
+          };
+        }) workers
+      );
+    };
+
+    services.nginx = {
+      upstreams = lib.listToAttrs (
+        lib.map (type: {
+          name = "${workerName}-${type}";
+          value = {
+            extraConfig = ''
+              keepalive 32;
+              least_conn;
+            '';
+            servers = lib.listToAttrs (
+              lib.map (index: {
+                name = "unix:/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                value = {
+                  max_fails = 0;
+                };
+              }) workers
+            );
+          };
+        }) enabledResources
+      );
+
+      virtualHosts."${cfg.nginxVirtualHostName}".locations = lib.listToAttrs (
+        lib.flatten (
+          lib.forEach enabledResources (
+            type:
+            lib.map (route: {
+              name = route;
+              value = {
+                proxyPass = "http://${workerName}-${type}";
+                extraConfig = ''
+                  proxy_http_version 1.1;
+                  proxy_set_header Connection "";
+                '';
+              };
+            }) workerRoutes.${type}
+          )
+        )
+      );
+    };
+  };
+}
diff --git a/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/to_device-stream-writer.nix b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/to_device-stream-writer.nix
new file mode 100644
index 0000000..e24c8a4
--- /dev/null
+++ b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/to_device-stream-writer.nix
@@ -0,0 +1,118 @@
+{ config, lib, ... }:
+
+let
+  cfg = config.services.matrix-synapse;
+  dbGroup = "medium";
+  streamWriterType = "to_device";
+  workers = lib.range 0 (cfg.toDeviceStreamWriters - 1);
+  workerName = "to_device_stream_writer";
+  workerRoutes = {
+    client = [ ];
+    federation = [ ];
+    media = [ ];
+  };
+in
+let
+  enabledResources =
+    lib.optionals (lib.length workerRoutes.client > 0) [ "client" ]
+    ++ lib.optionals (lib.length workerRoutes.federation > 0) [ "federation" ]
+    ++ lib.optionals (lib.length workerRoutes.media > 0) [ "media" ];
+in
+{
+  config = lib.mkIf (cfg.toDeviceStreamWriters > 0) {
+    monitoring.synapse.workerNames = lib.map (index: "${workerName}-${toString index}") workers;
+    services.matrix-synapse = {
+      settings = {
+        instance_map = lib.listToAttrs (
+          lib.map (index: {
+            name = "${workerName}-${toString index}";
+            value = {
+              path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+            };
+          }) workers
+        );
+
+        stream_writers.${streamWriterType} = lib.map (index: "${workerName}-${toString index}") workers;
+      };
+
+      workers = lib.listToAttrs (
+        lib.map (index: {
+          name = "${workerName}-${toString index}";
+          value = {
+            worker_app = "synapse.app.generic_worker";
+            worker_listeners =
+              [
+                {
+                  type = "http";
+                  path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+                  resources = [
+                    {
+                      names = [ "replication" ];
+                      compress = false;
+                    }
+                  ];
+                }
+              ]
+              ++ lib.map (type: {
+                type = "http";
+                path = "/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                mode = "666";
+                resources = [
+                  {
+                    names = [ type ];
+                    compress = false;
+                  }
+                ];
+              }) enabledResources;
+            database = (
+              import ../../db.nix {
+                inherit dbGroup;
+                workerName = "${workerName}-${toString index}";
+              }
+            );
+          };
+        }) workers
+      );
+    };
+
+    services.nginx = {
+      upstreams = lib.listToAttrs (
+        lib.map (type: {
+          name = "${workerName}-${type}";
+          value = {
+            extraConfig = ''
+              keepalive 32;
+              least_conn;
+            '';
+            servers = lib.listToAttrs (
+              lib.map (index: {
+                name = "unix:/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                value = {
+                  max_fails = 0;
+                };
+              }) workers
+            );
+          };
+        }) enabledResources
+      );
+
+      virtualHosts."${cfg.nginxVirtualHostName}".locations = lib.listToAttrs (
+        lib.flatten (
+          lib.forEach enabledResources (
+            type:
+            lib.map (route: {
+              name = route;
+              value = {
+                proxyPass = "http://${workerName}-${type}";
+                extraConfig = ''
+                  proxy_http_version 1.1;
+                  proxy_set_header Connection "";
+                '';
+              };
+            }) workerRoutes.${type}
+          )
+        )
+      );
+    };
+  };
+}
diff --git a/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/typing-stream-writer.nix b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/typing-stream-writer.nix
new file mode 100644
index 0000000..80e79a9
--- /dev/null
+++ b/host/Rory-nginx/services/matrix/synapse/workers/stream-writers/typing-stream-writer.nix
@@ -0,0 +1,118 @@
+{ config, lib, ... }:
+
+let
+  cfg = config.services.matrix-synapse;
+  dbGroup = "medium";
+  streamWriterType = "typing";
+  workers = lib.range 0 (cfg.typingStreamWriters - 1);
+  workerName = "typing_stream_writer";
+  workerRoutes = {
+    client = [ ];
+    federation = [ ];
+    media = [ ];
+  };
+in
+let
+  enabledResources =
+    lib.optionals (lib.length workerRoutes.client > 0) [ "client" ]
+    ++ lib.optionals (lib.length workerRoutes.federation > 0) [ "federation" ]
+    ++ lib.optionals (lib.length workerRoutes.media > 0) [ "media" ];
+in
+{
+  config = lib.mkIf (cfg.typingStreamWriters > 0) {
+    monitoring.synapse.workerNames = lib.map (index: "${workerName}-${toString index}") workers;
+    services.matrix-synapse = {
+      settings = {
+        instance_map = lib.listToAttrs (
+          lib.map (index: {
+            name = "${workerName}-${toString index}";
+            value = {
+              path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+            };
+          }) workers
+        );
+
+        stream_writers.${streamWriterType} = lib.map (index: "${workerName}-${toString index}") workers;
+      };
+
+      workers = lib.listToAttrs (
+        lib.map (index: {
+          name = "${workerName}-${toString index}";
+          value = {
+            worker_app = "synapse.app.generic_worker";
+            worker_listeners =
+              [
+                {
+                  type = "http";
+                  path = "/run/matrix-synapse/${workerName}-${toString index}.sock";
+                  resources = [
+                    {
+                      names = [ "replication" ];
+                      compress = false;
+                    }
+                  ];
+                }
+              ]
+              ++ lib.map (type: {
+                type = "http";
+                path = "/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                mode = "666";
+                resources = [
+                  {
+                    names = [ type ];
+                    compress = false;
+                  }
+                ];
+              }) enabledResources;
+            database = (
+              import ../../db.nix {
+                inherit dbGroup;
+                workerName = "${workerName}-${toString index}";
+              }
+            );
+          };
+        }) workers
+      );
+    };
+
+    services.nginx = {
+      upstreams = lib.listToAttrs (
+        lib.map (type: {
+          name = "${workerName}-${type}";
+          value = {
+            extraConfig = ''
+              keepalive 32;
+              least_conn;
+            '';
+            servers = lib.listToAttrs (
+              lib.map (index: {
+                name = "unix:/run/matrix-synapse/${workerName}-${type}-${toString index}.sock";
+                value = {
+                  max_fails = 0;
+                };
+              }) workers
+            );
+          };
+        }) enabledResources
+      );
+
+      virtualHosts."${cfg.nginxVirtualHostName}".locations = lib.listToAttrs (
+        lib.flatten (
+          lib.forEach enabledResources (
+            type:
+            lib.map (route: {
+              name = route;
+              value = {
+                proxyPass = "http://${workerName}-${type}";
+                extraConfig = ''
+                  proxy_http_version 1.1;
+                  proxy_set_header Connection "";
+                '';
+              };
+            }) workerRoutes.${type}
+          )
+        )
+      );
+    };
+  };
+}
diff --git a/modules/monitoring/synapse.nix b/modules/monitoring/synapse.nix
index 385e996..42eb4e7 100644
--- a/modules/monitoring/synapse.nix
+++ b/modules/monitoring/synapse.nix
@@ -47,7 +47,7 @@ in
       ]
       ++ lib.flatten (
         lib.imap (index: workerName: {
-          job_name = "synapse-${workerName}s";
+          job_name = "synapse-${workerName}";
           scrape_interval = "${toString cfg.prometheusScrapeInterval}s";
           static_configs = [
             {