diff --git a/modules/hosts/loptland/default.nix b/modules/hosts/loptland/default.nix index 44a3104..6335d8d 100644 --- a/modules/hosts/loptland/default.nix +++ b/modules/hosts/loptland/default.nix @@ -30,6 +30,9 @@ topLevel: { forgejo forgejo-runner + # services + matrix-synapse + # game server minecraft-server factorio-server diff --git a/modules/hosts/loptland/nginx.nix b/modules/hosts/loptland/nginx.nix index 0ceda04..d6b759d 100644 --- a/modules/hosts/loptland/nginx.nix +++ b/modules/hosts/loptland/nginx.nix @@ -50,6 +50,39 @@ }; }; + "matrix.alwayssleepy.online" = lib.mkIf config.services.matrix-synapse.enable { + forceSSL = true; + useACMEHost = "alwayssleepy.online"; + + locations."/" = { + proxyPass = "http://localhost:${toString 8008}"; + extraConfig = '' + client_max_body_size 50M; + ''; + }; + }; + + # .well-known Matrix delegation so Matrix IDs are @user:alwayssleepy.online + "alwayssleepy.online" = { + forceSSL = true; + useACMEHost = "alwayssleepy.online"; + + locations."/.well-known/matrix/server" = { + extraConfig = '' + default_type application/json; + return 200 '{"m.server":"matrix.alwayssleepy.online:443"}'; + ''; + }; + + locations."/.well-known/matrix/client" = { + extraConfig = '' + default_type application/json; + add_header 'Access-Control-Allow-Origin' '*'; + return 200 '{"m.homeserver":{"base_url":"https://matrix.alwayssleepy.online"}}'; + ''; + }; + }; + "nixcache.${domainName}" = lib.mkIf config.services.nix-serve.enable { forceSSL = true; useACMEHost = domainName; diff --git a/modules/server/acme.nix b/modules/server/acme.nix index 81d509f..a9f7a05 100644 --- a/modules/server/acme.nix +++ b/modules/server/acme.nix @@ -54,6 +54,16 @@ topLevel: { dnsResolver = "1.1.1.1:53"; extraDomainNames = [ "*.${domainname}" ]; }; + + certs."cholli.de" = { + dnsResolver = "1.1.1.1:53"; + extraDomainNames = [ "*.cholli.de" ]; + }; + + certs."alwayssleepy.online" = { + dnsResolver = "1.1.1.1:53"; + extraDomainNames = [ "*.alwayssleepy.online" ]; + }; }; }; diff --git a/modules/server/matrix-synapse.nix b/modules/server/matrix-synapse.nix new file mode 100644 index 0000000..1d1b59e --- /dev/null +++ b/modules/server/matrix-synapse.nix @@ -0,0 +1,98 @@ +{ + flake.modules.nixos.matrix-synapse = + { config, ... }: + let + domainName = "alwayssleepy.online"; + matrixPort = 8008; + sopsFile = ../../secrets/secrets-loptland.yaml; + in + { + sops.secrets."matrix/registrationSharedSecret" = { + inherit sopsFile; + owner = "matrix-synapse"; + }; + + services.postgresql = { + enable = true; + ensureDatabases = [ "matrix-synapse" ]; + ensureUsers = [ + { + name = "matrix-synapse"; + ensureDBOwnership = true; + } + ]; + }; + + # ensureDatabases creates with default collation, but Synapse requires C collation. + # This service runs after postgresql-setup (which runs ensureDatabases) and corrects + # the collation by recreating the DB if needed. + systemd.services."matrix-synapse-db-setup" = { + description = "Set up Matrix Synapse PostgreSQL database with C collation"; + wantedBy = [ "matrix-synapse.service" ]; + before = [ "matrix-synapse.service" ]; + after = [ + "postgresql.service" + "postgresql-setup.service" + ]; + requires = [ "postgresql.service" ]; + serviceConfig = { + Type = "oneshot"; + User = "postgres"; + RemainAfterExit = true; + }; + script = '' + COLLATION=$(psql -tAc "SELECT datcollate FROM pg_database WHERE datname = 'matrix-synapse'") + if [ "$COLLATION" != "C" ]; then + psql -c "DROP DATABASE \"matrix-synapse\"" + psql -c "CREATE DATABASE \"matrix-synapse\" ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE=template0 OWNER \"matrix-synapse\"" + fi + ''; + }; + + services.matrix-synapse = { + enable = true; + + settings = { + server_name = domainName; + + database = { + name = "psycopg2"; + args.database = "matrix-synapse"; + }; + + public_baseurl = "https://matrix.${domainName}"; + + listeners = [ + { + port = matrixPort; + bind_addresses = [ "127.0.0.1" ]; + type = "http"; + tls = false; + x_forwarded = true; + resources = [ + { + names = [ + "client" + "federation" + ]; + compress = false; + } + ]; + } + ]; + + enable_registration = true; + registration_requires_token = true; + }; + + extraConfigFiles = [ config.sops.templates."matrix-synapse-extra.yaml".path ]; + }; + + sops.templates."matrix-synapse-extra.yaml" = { + owner = "matrix-synapse"; + content = '' + registration_shared_secret: "${config.sops.placeholder."matrix/registrationSharedSecret"}" + ''; + }; + }; +} diff --git a/secrets/secrets-loptland.yaml b/secrets/secrets-loptland.yaml index 3201cb1..ad032e9 100644 --- a/secrets/secrets-loptland.yaml +++ b/secrets/secrets-loptland.yaml @@ -20,6 +20,8 @@ hydra: token: ENC[AES256_GCM,data:FqlJMfw7d1VfWhC+vI4SEMWzzADXK/np33fCsihq3wgC6nWNeTurNn1vDRLIRH+s6iT1C8Ni8iAAlndfUS5SPH6Ymswix9KuJCvYc8Jy+c8pPchYePtMQfv3dVe5a1i06b8I5c+MX8V7j2kaCijYDirnhiD0qlc8SW/mIyB5RNpAgKPTzLjLKJNSUkTGOWUnww==,iv:H2yQ5ioBVnezmhGHbJ7sAlXvUb2MUmHpQpS7f+nIph4=,tag:qvqsbgf2Y/PAd3s9ZFuxWA==,type:str] remotebuild: private-key: ENC[AES256_GCM,data:FqdXFj4/leKNtNJ1H1sBnb/Gnso9soaLtdUToMsx3O6LAn2smdkFrguY9EESm+o1nIBWwc1S2cE/sfH8FR89NWbyfCDTsQLHRIIEYMS2kKLv7hqqdsmyQojW38TnUYtSo5W1V9pdmeYuotUrM7bPmW/Io/7/G/vW6LxtI7Mx1qT7OXnyEJVYsvY6TtJitWO0/jGUAGOyvu/+YhV4yRmArM2kjT+iYb8/dN0HpqCwo6aLvY7ctAA6ggESciuovEtUMv19y+RpMUaHxloziM3SFz/GjXekrqtPGDkCUusSChXuhzfmZDoz4dzNnkKn8HsmxzByzaTyNH9kCxzNV7vULTKi6/O4ny64FOk6pjymz2Yv6pK+pm3tP2wrPwynn3C1giwFCGn+2Nazixj4g4wd5iSFwNeAsDbLU0b3YN/NgQv0TeKGXR01Xgqvt06vtAnkpu8byPBUX5cz15kJckeztVHYCQyz6Uthk6NN+ScLok1z3I7Vn37KsF0Ka7k22aPMwXLLKkfEneavT41x1VNBq7Nedf9EFjjUG8S7,iv:mTlEphmcoFMv7dxIeSpsi77e3CJULcXxcOF1Nq66mUM=,tag:K2aGpaw2xeEj8537kB/cGA==,type:str] +matrix: + registrationSharedSecret: ENC[AES256_GCM,data:6IBlAfQhWlywWo/l8u5gAfW7bTgXwrAyk8WBBWkJQK+FL9LvUU5hDscozHrPIiRRzZdyeoAZ7phirDk3kN9E6Q==,iv:arZaxnIEUU3psaV8PqKAb46nlq73r2SAVlmCY+y+HB0=,tag:X/zsAtryEfl2PHKQ6GQfbg==,type:str] sops: age: - recipient: age1pc92kl38mfr0j68dxww7tpzvqp3lpw6lwfylj6hn2k3rf4rddgtsjxdx47 @@ -40,7 +42,7 @@ sops: czdSTjNGSEpURlZEUTlIaUtGQUk5cW8KvylMTgtmHNvGnN7DonAsYQZB31mVli75 3OTN+mOetq2YNxh/Se7vqzwbZnshfTDk9nJi9bKZQhBt2nYR8eLRkg== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-12-01T21:50:41Z" - mac: ENC[AES256_GCM,data:rtICn+ljt414EWhSmVqM3IttqBx07a+m0MHEADNQ7s3USSfq3oEXqfoA1Nt6nIF/ZjNYeebNW9hiiJcZw/Hh749p3Fdu64w63MUTwsBciT651DwNNHJHVGwELaU72nI8amtVln+Ka0VD58/cM0V4mcw+eNvfUS+ykUVZAqmOiHo=,iv:IlgqHdb1gtajBfWogN6EgZ1V6h7ToTR1cArP8jEYocg=,tag:bagJOpWoMSvsgmKT/LsAJg==,type:str] + lastmodified: "2026-03-26T10:22:50Z" + mac: ENC[AES256_GCM,data:RFNQKhb5AGMNZuZ8efT8s2/DrwOaN+Lge4M2a36NOzuNJ4xTI3Xcp0vEqpARplF9PSBZ64asWYqu4e21+KfS76Is6EaSyvfUc53QoX38zjn6S7EobiVwkCXcEfOAXOd14qqQNOBHcC4ELI5Ah0N7x/iYjX2+BYILQQCcgAGnbDE=,iv:/vJ7JsiP8adC5IUBYod/iHA3qQtDfrV9fmaglZyzQCA=,tag:vy9FfzKXSCCBM3cVMcAcfQ==,type:str] unencrypted_suffix: _unencrypted version: 3.11.0