about summary refs log tree commit diff
path: root/modules/services/matrix-homeserver.nix
diff options
context:
space:
mode:
Diffstat (limited to 'modules/services/matrix-homeserver.nix')
-rw-r--r--modules/services/matrix-homeserver.nix190
1 files changed, 190 insertions, 0 deletions
diff --git a/modules/services/matrix-homeserver.nix b/modules/services/matrix-homeserver.nix
new file mode 100644
index 0000000..3dc188b
--- /dev/null
+++ b/modules/services/matrix-homeserver.nix
@@ -0,0 +1,190 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.modules.services.matrix-homeserver;
+
+  httpPort = 8008;
+  slidingSyncPort = 8009;
+  metricsPort = 8010;
+in
+{
+  options.modules.services.matrix-homeserver = {
+    enable = mkEnableOption "matrix homeserver instance";
+    domain = mkOption { type = types.str; };
+    realHost = mkOption { type = types.str; default = "matrix.${cfg.domain}"; };
+    slidingSyncHost = mkOption { type = types.str; default = "slidingsync.${cfg.domain}"; };
+    turn = {
+      enable = mkEnableOption "VOIP using TURN";
+      domain = mkOption { type = types.str; default = "turn.${cfg.domain}"; };
+      shared_secret = mkOption { type = types.str; };
+    };
+    secrets = {
+      matrix-server-key = mkOption { type = types.path; description = "path to the server key"; };
+      matrix-shared-secret = mkOption { type = types.path; description = "path to the registration shared secret"; };
+      extra-config-path = mkOption { type = types.nullOr types.path; description = "path to the extra configuration file to source"; };
+      sliding-sync-secret = mkOption { type = types.nullOr types.path; description = "path to the sliding sync secret"; };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.matrix-synapse = {
+      enable = true;
+      withJemalloc = true;
+      dataDir = "/var/lib/matrix-synapse";
+      settings = {
+        server_name = cfg.domain;
+        public_baseurl = "https://${cfg.realHost}";
+
+        signing_key_path = cfg.secrets.matrix-server-key;
+
+        allow_guest_access = false;
+        enable_registration = false;
+        registration_requires_token = true;
+        registration_shared_secret_path = cfg.secrets.matrix-shared-secret;
+
+        enable_metrics = true;
+        url_preview_enabled = true;
+
+        database = {
+          name = "psycopg2";
+          args.password = "synapse";
+        };
+
+        listeners = [
+          {
+            port = httpPort;
+            resources = [
+              {
+                compress = true;
+                names = [ "client" ];
+              }
+              {
+                compress = false;
+                names = [ "federation" ];
+              }
+            ];
+            type = "http";
+            tls = false;
+            x_forwarded = true;
+          }
+          {
+            port = metricsPort;
+            resources = [{
+              compress = false;
+              names = [ "metrics" ];
+            }];
+            type = "metrics";
+            tls = false;
+          }
+        ];
+
+        trusted_key_servers = [{
+          server_name = "matrix.org";
+          verify_keys = {
+            "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
+          };
+        }];
+        # Yes, we want to use matrix.org as our trusted key server
+        suppress_key_server_warning = true;
+      } // optionalAttrs (cfg.turn.enable) {
+        turn_uris = [
+          "turns:${cfg.turn.domain}?transport=udp"
+          "turns:${cfg.turn.domain}?transport=tcp"
+          "turn:${cfg.turn.domain}?transport=udp"
+          "turn:${cfg.turn.domain}?transport=tcp"
+        ];
+      };
+    };
+
+    services.matrix-sliding-sync = {
+      enable = true;
+      createDatabase = true;
+      settings = {
+        SYNCV3_SERVER = "https://${cfg.realHost}";
+        SYNCV3_BINDADDR = "[::1]:${toString slidingSyncPort}";
+      };
+      environmentFile = cfg.secrets.sliding-sync-secret;
+    };
+
+    services.prometheus.scrapeConfigs = [
+      {
+        job_name = "synapse";
+        metrics_path = "/_synapse/metrics";
+        static_configs = [{
+          targets = [ "127.0.0.1:${toString metricsPort}" ];
+        }];
+      }
+    ];
+
+    modules.persistence.directories = [
+      "/var/lib/matrix-synapse"
+    ];
+
+    services.postgresql.enable = true;
+    services.postgresql.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.nginx.virtualHosts.${cfg.realHost} = {
+      forceSSL = true;
+      useACMEHost = cfg.domain;
+      listen = [
+        { addr = "0.0.0.0"; port = 443; ssl = true; }
+        { addr = "[::]"; port = 443; ssl = true; }
+        { addr = "0.0.0.0"; port = 8448; ssl = true; }
+        { addr = "[::]"; port = 8448; ssl = true; }
+
+      ];
+      extraConfig = ''
+        proxy_set_header Host $host;
+        proxy_set_header X-Forwarded-For $remote_addr;
+        proxy_set_header X-Forwarded-Proto $scheme;
+        proxy_read_timeout 600;
+        client_max_body_size ${config.services.matrix-synapse.settings.max_upload_size};
+      '';
+
+      locations."~* ^(\\/_matrix|\\/_synapse\\/client)".proxyPass = "http://[::1]:${toString httpPort}";
+    };
+
+    services.nginx.virtualHosts.${cfg.domain} =
+      let
+        server-hello = { "m.server" = "${cfg.realHost}:443"; };
+        client-hello = {
+          "m.homeserver"."base_url" = "https://${cfg.realHost}";
+          "m.identity_server"."base_url" = "https://vector.im";
+          "org.matrix.msc3575.proxy"."url" = "https://${cfg.slidingSyncHost}";
+        };
+      in
+      {
+        forceSSL = true;
+        useACMEHost = cfg.domain;
+        locations = {
+          "/.well-known/matrix/server" = {
+            extraConfig = ''
+              add_header Content-Type application/json;
+              return 200 '${builtins.toJSON server-hello}';
+            '';
+          };
+          "/.well-known/matrix/client" = {
+            extraConfig = ''
+              add_header Content-Type application/json;
+              add_header Access-Control-Allow-Origin *;
+              return 200 '${builtins.toJSON client-hello}';
+            '';
+          };
+        };
+      };
+
+    services.nginx.virtualHosts.${cfg.slidingSyncHost} = {
+      forceSSL = true;
+      useACMEHost = cfg.domain;
+      locations."/".proxyPass = "http://${config.services.matrix-sliding-sync.settings.SYNCV3_BINDADDR}";
+    };
+
+    networking.firewall.allowedTCPPorts = [ 443 8448 ];
+  };
+}