diff --git a/hosts/cube/matrix-synapse.nix b/hosts/cube/matrix-synapse.nix new file mode 100644 index 0000000..cf97d5c --- /dev/null +++ b/hosts/cube/matrix-synapse.nix @@ -0,0 +1,138 @@ +{ config, ulib, ... }: with ulib; + +let + inherit (config.networking) domain; + + chatDomain = "chat.${domain}"; + + wellKnownResponse = data: '' + add_header Content-Type application/json; + add_header Access-Control-Allow-Origin *; + return 200 '${builtins.toJSON data}'; + ''; + + clientConfig."m.homeserver".base_url = chatDomain; + serverConfig."m.server" = "${chatDomain}:443"; + + synapsePort = 8001; + slidingSyncPort = 8002; + exporterPort = 9060; +in serverSystemConfiguration { + age.secrets."cube/password.secret.matrix-synapse".owner = "matrix-synapse"; + age.secrets."cube/password.sync.matrix-synapse".owner = "matrix-synapse"; + + services.prometheus = { + scrapeConfigs = [{ + job_name = "matrix-synapse"; + metrics_path = "/_synapse/metrics"; + + static_configs = [{ + labels.job = "matrix-synapse"; + targets = [ + "[::]:${toString exporterPort}" + ]; + }]; + }]; + }; + + services.postgresql = { + ensureDatabases = [ "matrix-synapse" "matrix-sliding-sync" ]; + ensureUsers = [ + { + name = "matrix-synapse"; + ensureDBOwnership = true; + } + { + name = "matrix-sliding-sync"; + ensureDBOwnership = true; + } + ]; + }; + + services.matrix-synapse = enabled { + withJemalloc = true; + + configureRedisLocally = true; + settings.redis.enabled = true; + + extras = [ "postgres" "url-preview" "user-search" ]; + + settings = { + server_name = domain; + # We are not setting web_client_location since the root is not accessible + # from the outside web at all. Only /_matrix is reverse proxied to. + + database.name = "psycopg2"; + + report_stats = false; + + enable_metrics = true; + metrics_flags.known_servers = true; + + allow_guest_access = false; + enable_registration = false; + + expire_access_token = true; + url_preview_enabled = true; + + # Trusting Matrix.org. + suppress_key_server_warning = true; + }; + + # Sets registration_shared_secret. + extraConfigFiles = [ config.age.secrets."cube/password.secret.matrix-synapse".path ]; + + settings.listeners = [ + { + port = synapsePort; + + bind_addresses = [ "::" ]; + tls = false; + type = "http"; + x_forwarded = true; + + resources = [{ + compress = false; + names = [ "client" "federation" ]; + }]; + } + { + port = exporterPort; + + bind_addresses = [ "::" ]; + tls = false; + type = "metrics"; + + resources = []; + } + ]; + }; + + services.matrix-sliding-sync = enabled { + settings = { + SYNCV3_SERVER = "https://${chatDomain}"; + SYNCV3_DB = "postgresql:///matrix-sliding-sync?host=/run/postgresql"; + SYNCV3_BINDADDR = "[::]:${toString slidingSyncPort}"; + }; + environmentFile = config.age.secrets."cube/password.sync.matrix-synapse".path; + }; + + services.nginx.virtualHosts.${domain}.locations = { + "= /.well-known/matrix/client".extraConfig = wellKnownResponse clientConfig; + "= /.well-known/matrix/server".extraConfig = wellKnownResponse serverConfig; + }; + + services.nginx.virtualHosts.${chatDomain} = { + forceSSL = true; + useACMEHost = domain; + + locations."/".proxyPass = "http://[::]:${toString config.services.site.port}/404"; + locations."/assets".proxyPass = "http://[::]:${toString config.services.site.port}/assets"; + + locations."= /.well-known/matrix/client".extraConfig = wellKnownResponse clientConfig; + locations."= /.well-known/matrix/server".extraConfig = wellKnownResponse serverConfig; + + locations."/_matrix".proxyPass = "http://[::]:${toString synapsePort}"; + locations."/_synapse/client".proxyPass = "http://[::]:${toString synapsePort}"; + }; +} diff --git a/hosts/cube/matrix.nix b/hosts/cube/matrix.nix deleted file mode 100644 index 3bd251a..0000000 --- a/hosts/cube/matrix.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ config, ulib, ... }: with ulib; - -# Documenting this because I found the way Matrix works a bit weird: -# -# Since it uses normal plain HTTP on ports 80 and 443, we are using -# the root domain and proxying ${domain}/_matrix to the local matrix -# instance that is running. This means there are no matrix or chat -# or whatever 3rd level domains in this setup. The server url is -# the root, everywhere. - -let - inherit (config.networking) domain; -in serverSystemConfiguration { - age.secrets."cube/password.matrix".owner = "matrix"; - age.secrets."cube/password.matrix.sync".owner = "matrix"; - - services.postgresql = { - ensureDatabases = [ "matrix" ]; - ensureUsers = [{ - name = "matrix"; - ensureDBOwnership = true; - }]; - }; - - services.matrix-synapse = { # enabled { - settings = { - server_name = domain; - }; - }; -} diff --git a/hosts/cube/nginx.nix b/hosts/cube/nginx.nix index 045e3b1..ebb4eb7 100644 --- a/hosts/cube/nginx.nix +++ b/hosts/cube/nginx.nix @@ -29,7 +29,7 @@ serverSystemConfiguration { recommendedProxySettings = true; recommendedTlsSettings = true; - appendHttpConfig = '' + commonHttpConfig = '' map $scheme $hsts_header { https "max-age=31536000; includeSubdomains; preload"; } @@ -39,9 +39,9 @@ serverSystemConfiguration { add_header "Referrer-Policy" "no-referrer"; - add_header X-Frame-Options DENY; + # add_header X-Frame-Options DENY; - add_header X-Content-Type-Options nosniff; + # add_header X-Content-Type-Options nosniff; proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict"; ''; diff --git a/secrets/cube/password.secret.matrix-synapse.age b/secrets/cube/password.secret.matrix-synapse.age new file mode 100644 index 0000000..9b9c213 Binary files /dev/null and b/secrets/cube/password.secret.matrix-synapse.age differ diff --git a/secrets/cube/password.sync.matrix-synapse.age b/secrets/cube/password.sync.matrix-synapse.age new file mode 100644 index 0000000..6d47c5b Binary files /dev/null and b/secrets/cube/password.sync.matrix-synapse.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 9823c4b..95f7926 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -18,6 +18,9 @@ in with keys; { "cube/password.grafana.age".publicKeys = key cube; "cube/password.mail.grafana.age".publicKeys = key cube; + "cube/password.secret.matrix-synapse.age".publicKeys = key cube; + "cube/password.sync.matrix-synapse.age".publicKeys = key cube; + "cube/password.nextcloud.age".publicKeys = key cube; "enka/password.hash.orhan.age".publicKeys = key rgbcube;