From fc6f9f8987135aef2b364f5442d5c24dafc6a4d1 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Tue, 4 Apr 2023 11:29:56 +0200 Subject: [PATCH] Host multiple conduit instances --- modules/cloud/conduit/default.nix | 182 ++++++++++++++++++------- modules/cloud/conduit/heisenbridge.nix | 9 +- nki-personal-do/configuration.nix | 24 ++++ nki-personal-do/secrets/secrets.yaml | 5 +- 4 files changed, 167 insertions(+), 53 deletions(-) diff --git a/modules/cloud/conduit/default.nix b/modules/cloud/conduit/default.nix index bd33285..8ff21e5 100644 --- a/modules/cloud/conduit/default.nix +++ b/modules/cloud/conduit/default.nix @@ -2,6 +2,24 @@ let cfg = config.cloud.conduit; + + defaultConfig = { + global = { + # Must be filled + # server_name = ""; + # Must be filled + # port = ""; + max_request_size = 20000000; + allow_registration = false; + allow_encryption = true; + allow_federation = true; + trusted_servers = [ "matrix.org" ]; + address = "::1"; + # Must be filled + # database_path = ""; + database_backend = "rocksdb"; + }; + }; in with lib; { @@ -14,62 +32,132 @@ with lib; default = pkgs.matrix-conduit; }; - host = mkOption { - type = types.str; - default = "m.nkagami.me"; - }; - - port = mkOption { - type = types.int; - default = 6167; - }; - - allow_registration = mkOption { - type = types.bool; - default = false; - }; - - well-known_port = mkOption { - type = types.int; - default = 6166; + instances = mkOption { + type = types.attrsOf (types.submodule { + options = { + host = mkOption { + type = types.str; + }; + server_name = mkOption { + type = types.str; + default = ""; + }; + port = mkOption { + type = types.int; + }; + allow_registration = mkOption { + type = types.bool; + default = false; + }; + well-known_port = mkOption { + type = types.int; + }; + }; + }); }; }; - config.services.matrix-conduit = mkIf cfg.enable { - inherit (cfg) package; - enable = true; - - settings.global = { - inherit (cfg) port allow_registration; - server_name = cfg.host; - database_backend = "rocksdb"; - }; - }; + config.systemd.services = mkIf cfg.enable + (lib.attrsets.mapAttrs' + (name: instance: lib.attrsets.nameValuePair "matrix-conduit-${name}" + ( + let + srvName = "matrix-conduit-${name}"; + format = pkgs.formats.toml { }; + server_name = if instance.server_name == "" then instance.host else instance.server_name; + configFile = format.generate "conduit.toml" (lib.attrsets.recursiveUpdate defaultConfig { + global.server_name = server_name; + global.port = instance.port; + global.allow_registration = instance.allow_registration; + global.database_path = "/var/lib/${srvName}/"; + }); + in + { + description = "Conduit Matrix Server (for ${server_name})"; + documentation = [ "https://gitlab.com/famedly/conduit/" ]; + wantedBy = [ "multi-user.target" ]; + environment = { CONDUIT_CONFIG = configFile; }; + serviceConfig = { + DynamicUser = true; + User = "${srvName}"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + PrivateDevices = true; + PrivateMounts = true; + PrivateUsers = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + ]; + StateDirectory = "${srvName}"; + ExecStart = "${cfg.package}/bin/conduit"; + Restart = "on-failure"; + RestartSec = 10; + StartLimitBurst = 5; + }; + } + )) + cfg.instances); # Serving .well-known files # This is a single .well-known/matrix/server file that points to the server, # which is NOT on port 8448 since Cloudflare doesn't allow us to route HTTPS # through that port. - config.services.nginx = mkIf cfg.enable { - enable = true; - virtualHosts.conduit-well-kwown = { - listen = [{ addr = "127.0.0.1"; port = cfg.well-known_port; }]; - # Check https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-well-known.md - # for the file structure. - root = pkgs.writeTextDir ".well-known/matrix/server" '' - { - "m.server": "${cfg.host}:443" - } - ''; + config.services.nginx = mkIf cfg.enable + { + enable = true; + virtualHosts = lib.attrsets.mapAttrs' + (name: instance: lib.attrsets.nameValuePair "conduit-${name}-well-known" { + listen = [{ addr = "127.0.0.1"; port = instance.well-known_port; }]; + # Check https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-well-known.md + # for the file structure. + root = pkgs.symlinkJoin + { + name = "well-known-files-for-conduit-${name}"; + paths = [ + (pkgs.writeTextDir ".well-known/matrix/client" (builtins.toJSON { + "m.homeserver".base_url = "https://${instance.host}"; + })) + (pkgs.writeTextDir ".well-known/matrix/server" (builtins.toJSON { + "m.server" = "${instance.host}:443"; + })) + ]; + }; + # Enable CORS from anywhere since we want all clients to find us out + extraConfig = '' + add_header 'Access-Control-Allow-Origin' "*"; + ''; + }) + cfg.instances; }; - }; - config.cloud.traefik.hosts = mkIf cfg.enable { - conduit = { inherit (cfg) port host; }; - conduit-well-kwown = { - port = cfg.well-known_port; - filter = "Host(`${cfg.host}`) && PathPrefix(`/.well-known`)"; - }; - }; + config.cloud.traefik.hosts = mkIf cfg.enable ( + (lib.attrsets.mapAttrs' + (name: instance: lib.attrsets.nameValuePair "conduit-${name}" ({ + inherit (instance) host port; + })) + cfg.instances) + // (lib.attrsets.mapAttrs' + (name: instance: lib.attrsets.nameValuePair "conduit-${name}-well-known" ( + let + server_name = if instance.server_name == "" then instance.host else instance.server_name; + in + { + port = instance.well-known_port; + filter = "Host(`${server_name}`) && PathPrefix(`/.well-known`)"; + } + )) + cfg.instances) + ); } diff --git a/modules/cloud/conduit/heisenbridge.nix b/modules/cloud/conduit/heisenbridge.nix index 76661e0..0a7bc79 100644 --- a/modules/cloud/conduit/heisenbridge.nix +++ b/modules/cloud/conduit/heisenbridge.nix @@ -16,6 +16,10 @@ with lib; { description = "The port to listen to. Leave blank to just use the appserviceFile's configuration"; default = null; }; + homeserver = mkOption { + type = types.str; + description = "The homeserver to listen to"; + }; }; config = mkIf cfg.enable ( let @@ -43,10 +47,7 @@ with lib; { cfgFile ] ++ listenArgs - ++ [ - # Homeserver - "https://${toString cfgConduit.host}" - ] + ++ [ cfg.homeserver ] ); # Hardening options diff --git a/nki-personal-do/configuration.nix b/nki-personal-do/configuration.nix index 8a6ec15..1f11d68 100644 --- a/nki-personal-do/configuration.nix +++ b/nki-personal-do/configuration.nix @@ -67,8 +67,22 @@ # Conduit sops.secrets.heisenbridge = { owner = "heisenbridge"; }; + sops.secrets.matrix-discord-bridge = { mode = "0644"; }; cloud.conduit.enable = true; cloud.conduit.package = pkgs.unstable.matrix-conduit; + cloud.conduit.instances = { + "nkagami" = { + host = "m.nkagami.me"; + port = 6167; + well-known_port = 6168; + }; + "dtth" = { + host = "m.dtth.ch"; + server_name = "dtth.ch"; + port = 6169; + well-known_port = 6170; + }; + }; cloud.conduit.heisenbridge = { enable = true; package = pkgs.heisenbridge.overrideAttrs (old: rec { @@ -82,6 +96,16 @@ }; }); appserviceFile = config.sops.secrets.heisenbridge.path; + homeserver = "https://m.nkagami.me"; + }; + services.matrix-appservice-discord = { + enable = true; + environmentFile = config.sops.secrets.matrix-discord-bridge.path; + serviceDependencies = [ "matrix-conduit-dtth.service" ]; + settings.bridge = { + domain = "dtth.ch"; + homeserverUrl = "https://m.dtth.ch:443"; + }; }; # Navidrome back to the PC diff --git a/nki-personal-do/secrets/secrets.yaml b/nki-personal-do/secrets/secrets.yaml index f1970ee..ffa0f1b 100644 --- a/nki-personal-do/secrets/secrets.yaml +++ b/nki-personal-do/secrets/secrets.yaml @@ -12,6 +12,7 @@ youmubot-env: ENC[AES256_GCM,data:m/NGN8r6Caq2tTHeVWV9y5fol9r36aKYYXLjHaa0AR+0Xp outline: smtp-password: ENC[AES256_GCM,data:zpIi6jVB2Y7ksBOR8SGFgjOD1x3aS6dKa6taLKB8v2l9p92iWDti75qgB1puglmmq8mCzz8KXLrM0Bv7W8GWRg==,iv:6tKINzQcApmNuIbNn0kSzFJtwn3rky/uFG2Ff3lazUk=,tag:kjB6qB87tRQVpy32Pt3D5A==,type:str] heisenbridge: ENC[AES256_GCM,data:rJY7gpcOY8nODR3KlYW1rEs54mKxr+AjNBeg1/2vTG0Gzpuvjgbnn5UVJS+P8uej/P4HfeFtlQSFZCEy8cXcwvwq97ppVliCGL4GMLRWaFmop35feC8t2ovh79cy/vKC7drASeGvWYNUmGRjboPuKA8W5LARa0HVDPGDLIEMVgJfYry/YKR3gsGmLzU7Mx1yLO6M/EFOJQJc84bSuu+CPSZcyUVF4SSNBiaDU5/NazlqaA9KWL6Xzu1MD2LEYdEFkRfitNgYj2m2gLd9voyGV4cfaCqJvYjJPwuZeZUoqCpDnom2JoV29q/Yq/gmyumPgOvriGxLsYBqV14MaCcE6KXE2uLicD+I/5or1AxepVDVjG9NoSgho1HpLvpRhMSCeXLk9+U+ykH3QA+0M+VVu9pswMMVQifnTtXZRM6pWxOnRVAzGf2tGDo4jy36S7pHaRn7SJcrljjWLfwHuNiu7E2uZhMrkcCjnjcBA9Xrb3drDQYVHya7XcoD4wOBHBDvVZwhYkNdkS3oYkom8A==,iv:fO1onfon3EdSNC/LjN1aWxpHBYq5aa0F/h0V6gl88ac=,tag:NL9p2nhIlEqgOdvUDM19Dg==,type:str] +matrix-discord-bridge: ENC[AES256_GCM,data:/rlSjD6inKfak7HKKghH5ays5RjKmb9czGsoIOYHyTZC4A5EMucCbfn8DL1gkYXgvRHJ+QglGX/BGo5ebaxSj6nF60+aW87UG31KggOt5kkMuWsPsjvrufoc5IlNfWnXIWmqf8cdC01hmHEp7biUpI8CcfEZiD9OkOxbZcRfYqW+ttnzplFniRBjGPVZfL5g4DBbuJen5MuOrrMDo5CT+78n,iv:r9VBbDCAAElisCaDehrB6PhJHsaaHjdrk3103lmBT7o=,tag:WoNMMfyMifsL56yWq3MUOg==,type:str] sops: kms: [] gcp_kms: [] @@ -45,8 +46,8 @@ sops: by9kZFlTRVdCZFkxYTVVb0RIRk8zUlkKCqMw9oL9RaYBV5Hhy3o8Nm5xmGrPH8Sd hv36sxRFFNZT/DCKaHaSRbT3mfpBZSTXJt1dgl4nZe6whH54t/1KmA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-03-31T09:59:11Z" - mac: ENC[AES256_GCM,data:OqxOvJGa7v7+SUyuTMjc02kvLS3R+TmGu7DqaYWv0tdrHpbsIwqbA6l2Ex046I28mG+SPbfgsDxMXkNKjSVkjqR1UBvRrdJMM0MPinlUebi2egwqwRj/QbPjyvWPYMTqQBwucBEW98IuQEo77HDSfQ0727PXQiBINoXTU0oGg2M=,iv:xg1sAecRMLd+ZH44ehCxkS+E4e+7R0NIiMjafaP4chg=,tag:bv4FEzZO0CTOl3mvHSDEyA==,type:str] + lastmodified: "2023-04-03T20:09:31Z" + mac: ENC[AES256_GCM,data:7TBLlaplxp6+/qXgx6LDVywqqhIHRn3gw2287cVEHHTr7wLdZMle1EvRSAFP+2jYeAAhie/MaLvFKYSEZ2KHHVwvtBRS08ieJ2lnsIWRqkYVxFPgOeCCJei1IuEXKxmDB2yRGV/paE6w/1HW3j5iaVh1TIjkHpKDqpsMdFcYoZw=,iv:CSHDBO1crdJilcHFkxDQMNWk/ClsyV/g4aDECPMpT7E=,tag:r9LRx0Ler7dDXhkNp9pTLA==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.7.3