summaryrefslogtreecommitdiff
path: root/modules/nixos/matrix
diff options
context:
space:
mode:
Diffstat (limited to 'modules/nixos/matrix')
-rw-r--r--modules/nixos/matrix/default.nix1
-rw-r--r--modules/nixos/matrix/dendrite.nix157
-rw-r--r--modules/nixos/matrix/element.nix59
-rw-r--r--modules/nixos/matrix/synapse.nix93
4 files changed, 310 insertions, 0 deletions
diff --git a/modules/nixos/matrix/default.nix b/modules/nixos/matrix/default.nix
new file mode 100644
index 0000000..bd221c4
--- /dev/null
+++ b/modules/nixos/matrix/default.nix
@@ -0,0 +1 @@
+_: {imports = [./dendrite.nix ./element.nix ./synapse.nix];}
diff --git a/modules/nixos/matrix/dendrite.nix b/modules/nixos/matrix/dendrite.nix
new file mode 100644
index 0000000..0fad5f2
--- /dev/null
+++ b/modules/nixos/matrix/dendrite.nix
@@ -0,0 +1,157 @@
+{
+ config,
+ lib,
+ inputs,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.nixfiles.modules.matrix.dendrite;
+in {
+ options.nixfiles.modules.matrix.dendrite = {
+ enable = mkEnableOption "Dendrite Matrix server";
+
+ domain = mkOption {
+ type = types.str;
+ default = config.networking.domain;
+ description = "Domain name sans protocol scheme.";
+ };
+ };
+
+ config = let
+ db = "dendrite";
+ in
+ mkIf cfg.enable {
+ secrets.dendrite-private-key = {
+ file = "${inputs.self}/secrets/dendrite-private-key";
+ mode = "0444"; # The user is dynamic so the file must be world-readable.
+ };
+ secrets.dendrite-environment-file = {
+ file = "${inputs.self}/secrets/dendrite-environment-file";
+ mode = "0444"; # The user is dynamic so the file must be world-readable.
+ };
+
+ nixfiles.modules = {
+ nginx = {
+ enable = true;
+ upstreams.dendrite.servers."127.0.0.1:${toString config.services.dendrite.httpPort}" = {};
+ virtualHosts.${cfg.domain}.locations = {
+ "/_matrix".proxyPass = "http://dendrite";
+ "= /.well-known/matrix/server" = {
+ extraConfig = ''
+ add_header Content-Type application/json;
+ '';
+ return = "200 '${
+ generators.toJSON {} {"m.server" = "${cfg.domain}:443";}
+ }'";
+ };
+ "= /.well-known/matrix/client" = {
+ extraConfig = ''
+ add_header Content-Type application/json;
+ add_header Access-Control-Allow-Origin *;
+ '';
+ return = "200 '${
+ generators.toJSON {} {
+ "m.homeserver".base_url = "https://${cfg.domain}";
+ }
+ }'";
+ };
+ };
+ };
+ postgresql = {
+ enable = true;
+ extraPostStart = [
+ ''
+ $PSQL "${db}" -tAc 'GRANT ALL ON SCHEMA "public" TO "${db}"'
+ ''
+ ];
+ };
+ };
+
+ services = {
+ dendrite = {
+ enable = true;
+ httpPort = 8008;
+ environmentFile = config.secrets.dendrite-environment-file.path;
+ settings = {
+ version = 2;
+ global = {
+ server_name = cfg.domain;
+ private_key = config.secrets.dendrite-private-key.path;
+ database = {
+ connection_string = "postgresql://${db}@/${db}?host=/run/postgresql";
+ max_open_conns = 64;
+ max_idle_connections = 8;
+ };
+ cache = {
+ max_size_estimated = "1gb";
+ max_age = "1h";
+ };
+ trusted_third_party_id_servers = [
+ "matrix.org"
+ "nixos.org"
+ "vector.im"
+ ];
+ presence = {
+ enable_inbound = false;
+ enable_outbound = false;
+ };
+ };
+ client_api = {
+ registration_disabled = true;
+ guests_disabled = true;
+ registration_shared_secret = "$REGISTRATION_SHARED_SECRET";
+ };
+ media_api = {
+ max_file_size_bytes = 0;
+ dynamic_thumbnails = true;
+ max_thumbnail_generators = 8;
+ thumbnail_sizes = [
+ {
+ width = 32;
+ height = 32;
+ method = "crop";
+ }
+ {
+ width = 96;
+ height = 96;
+ method = "crop";
+ }
+ {
+ width = 640;
+ height = 480;
+ method = "scale";
+ }
+ ];
+ };
+ logging = [
+ {
+ type = "std";
+ level = "warn";
+ }
+ ];
+ };
+ };
+
+ postgresql = {
+ ensureDatabases = [db];
+ ensureUsers = [
+ {
+ name = db;
+ ensurePermissions."DATABASE \"${db}\"" = "ALL";
+ }
+ ];
+ };
+ };
+
+ systemd.services.dendrite.serviceConfig.ExecStart =
+ mkForce
+ (concatStringsSep " " [
+ "${pkgs.dendrite}/bin/dendrite-monolith-server"
+ "--config /run/dendrite/dendrite.yaml"
+ "--http-bind-address 127.0.0.1:${
+ toString config.services.dendrite.httpPort
+ }"
+ ]);
+ };
+}
diff --git a/modules/nixos/matrix/element.nix b/modules/nixos/matrix/element.nix
new file mode 100644
index 0000000..3d47800
--- /dev/null
+++ b/modules/nixos/matrix/element.nix
@@ -0,0 +1,59 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.nixfiles.modules.matrix.element;
+in {
+ options.nixfiles.modules.matrix.element = {
+ enable = mkEnableOption "Element, a Matrix web interface";
+
+ domain = mkOption {
+ description = "Domain name sans protocol scheme.";
+ type = with types; nullOr str;
+ default = "element.${config.networking.domain}";
+ };
+
+ homeserver = mkOption {
+ description = "Default Matrix homeserver.";
+ type = with types; str;
+ default = my.domain.azahi;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = with config.nixfiles.modules.matrix;
+ (synapse.enable || dendrite.enable) && !(!synapse.enable && !dendrite.enable);
+ message = "Synapse or Dendrite must be enabled";
+ }
+ ];
+
+ nixfiles.modules.nginx = with cfg; {
+ enable = true;
+ virtualHosts.${domain}.locations."/".root = pkgs.element-web.override {
+ conf = {
+ default_server_config."m.homeserver" = {
+ base_url = "https://${homeserver}";
+ server_name = homeserver;
+ };
+ disable_custom_urls = true;
+ disable_guests = true;
+ disable_login_language_selector = true;
+ disable_3pid_login = true;
+ brand = homeserver;
+ branding.authFooterLinks = [
+ {
+ text = "Hosted on NixOS";
+ url = "https://nixos.org";
+ }
+ ];
+ default_theme = "dark";
+ };
+ };
+ };
+ };
+}
diff --git a/modules/nixos/matrix/synapse.nix b/modules/nixos/matrix/synapse.nix
new file mode 100644
index 0000000..6ff5e0d
--- /dev/null
+++ b/modules/nixos/matrix/synapse.nix
@@ -0,0 +1,93 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.nixfiles.modules.matrix.synapse;
+in {
+ options.nixfiles.modules.matrix.synapse = {
+ enable = mkEnableOption "Synapse Matrix server";
+
+ domain = mkOption {
+ description = "Domain name sans protocol scheme.";
+ type = with types; str;
+ default = config.networking.domain;
+ };
+ };
+
+ config = let
+ bind_address = "127.0.0.1";
+ port = 8448;
+ in
+ mkIf cfg.enable {
+ nixfiles.modules = {
+ nginx = {
+ enable = true;
+ upstreams.synapse.servers."${bind_address}:${toString port}" = {};
+ virtualHosts.${cfg.domain}.locations = {
+ "~ ^(/_matrix|/_synapse/client)".proxyPass = "http://synapse";
+ "= /.well-known/matrix/server" = {
+ extraConfig = ''
+ add_header Content-Type application/json;
+ '';
+ return = "200 '${
+ generators.toJSON {} {"m.server" = "${cfg.domain}:443";}
+ }'";
+ };
+ "= /.well-known/matrix/client" = {
+ extraConfig = ''
+ add_header Content-Type application/json;
+ add_header Access-Control-Allow-Origin *;
+ '';
+ return = "200 '${
+ generators.toJSON {} {
+ "m.homeserver".base_url = "https://${cfg.domain}";
+ }
+ }'";
+ };
+ };
+ };
+ postgresql.enable = true;
+ };
+
+ services = let
+ db = "synapse";
+ in {
+ matrix-synapse = {
+ enable = true;
+ server_name = config.networking.domain;
+
+ database_type = "psycopg2";
+ database_name = db;
+ database_user = db;
+
+ listeners = [
+ {
+ inherit bind_address port;
+ type = "http";
+ tls = false;
+ x_forwarded = true;
+ resources = [
+ {
+ names = ["client" "federation"];
+ compress = false;
+ }
+ ];
+ }
+ ];
+ };
+
+ postgresql = {
+ ensureDatabases = [db];
+ ensureUsers = [
+ {
+ name = db;
+ ensurePermissions."DATABASE \"${db}\"" = "ALL";
+ }
+ ];
+ };
+ };
+ };
+}