{ config, pkgs, ... }: let # 1. create DNS entry `matrix.terranix.org A - 95.216.66.212` # 2. test with : https://federationtester.matrix.org/#terranix.org # 3. info at : https://silvio.github.io/docker-matrix/Example.configs.html name = "terranix"; domain = "terranix.org"; baseUrl = "https://matrix.${domain}"; synapse_port = 8008; federation_port = 8448; matrix_create_user = pkgs.writers.writeBashBin "matrix-create-user-${name}" '' ${pkgs.matrix-synapse}/bin/register_new_matrix_user \ -k $( ${pkgs.gojq}/bin/gojq \ --yaml-input \ --raw-output \ '.registration_shared_secret' \ ${config.sops.secrets.matrix_shared_secret.path} ) \ http://localhost:${toString synapse_port} ''; clientConfig."m.homeserver".base_url = baseUrl; serverConfig."m.server" = "matrix.${domain}:443"; mkWellKnown = data: '' default_type application/json; add_header Access-Control-Allow-Origin *; return 200 '${builtins.toJSON data}'; ''; element-web = pkgs.runCommand "element-web-with-config" { nativeBuildInputs = [ pkgs.buildPackages.jq ]; } '' cp -r ${pkgs.element-web} $out chmod -R u+w $out jq '."default_server_config"."m.homeserver" = { "base_url": "https://matrix.${domain}", "server_name": "${domain}" }' \ > $out/config.json < ${pkgs.element-web}/config.json ln -s $out/config.json $out/config.matrix.${domain}.json ''; in { networking.firewall.allowedTCPPorts = [ 80 443 federation_port ]; networking.firewall.allowedUDPPorts = [ 80 443 federation_port ]; environment.systemPackages = [ matrix_create_user ]; sops.secrets.matrix_shared_secret.owner = "matrix-synapse"; users.users.matrix-synapse = { isSystemUser = true; uid = config.ids.uids.matrix-synapse; group = "matrix-synapse"; }; users.groups.matrix-synapse.gid = config.ids.gids.matrix-synapse; containers."matrix-${name}" = { autoStart = true; privateNetwork = false; bindMounts = { rootpassword = { hostPath = config.sops.secrets.matrix_shared_secret.path; mountPoint = "/run/secrets/matrix-shared-secret"; isReadOnly = true; }; }; config = { config, pkgs, lib, ... }: { system.stateVersion = "23.11"; services.postgresql = { enable = true; 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.matrix-synapse = { enable = true; settings.server_name = domain; # The public base URL value must match the `base_url` value set in `clientConfig` above. # The default value here is based on `server_name`, so if your `server_name` is different # from the value of `matrix.` above, you will likely run into some mismatched domain names # in client applications. settings.public_baseurl = baseUrl; extraConfigFiles = [ "/run/secrets/matrix-shared-secret" ]; settings.listeners = [ { port = synapse_port; bind_addresses = [ "::1" ]; type = "http"; tls = false; x_forwarded = true; resources = [ { names = [ "client" ]; compress = true; } { names = [ "federation" ]; compress = false; } ]; } ]; }; }; }; services.nginx = { enable = true; recommendedTlsSettings = true; recommendedOptimisation = true; recommendedGzipSettings = true; recommendedProxySettings = true; virtualHosts = { # lives on another host # # If the A and AAAA DNS records on example.org do not point on the same host as the # # records for myhostname.example.org, you can easily move the /.well-known # # virtualHost section of the code to the host that is serving example.org, while # # the rest stays on myhostname.example.org with no other changes required. # # This pattern also allows to seamlessly move the homeserver from # # myhostname.example.org to myotherhost.example.org by only changing the # # /.well-known redirection target. # "${domain}" = { # enableACME = true; # forceSSL = true; # # This section is not needed if the server_name of matrix-synapse is equal to # # the domain (i.e. example.org from @foo:example.org) and the federation port # # is federation_port. # # Further reference can be found in the docs about delegation under # # https://element-hq.github.io/synapse/latest/delegate.html # locations."= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; # # This is usually needed for homeserver discovery (from e.g. other Matrix clients). # # Further reference can be found in the upstream docs at # # https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixclient # locations."= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; # }; "matrix.${domain}" = { listen = [ { addr = "0.0.0.0"; port = 80; } { addr = "0.0.0.0"; port = 443; ssl = true; } # for federation { addr = "0.0.0.0"; port = federation_port; ssl = true; } ]; enableACME = true; forceSSL = true; # It's also possible to do a redirect here or something else, this vhost is not # needed for Matrix. It's recommended though to *not put* element # here, see also the section about Element. locations."/".extraConfig = '' return 404; ''; # Forward all Matrix API calls to the synapse Matrix homeserver. A trailing slash # *must not* be used here. locations."/_matrix".proxyPass = "http://[::1]:${toString synapse_port}"; # Forward requests for e.g. SSO and password-resets. #locations."/_synapse/client".proxyPass = "http://[::1]:${toString synapse_port}"; }; "element.${domain}" = { forceSSL = true; enableACME = true; extraConfig = '' proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 600; ''; locations."/".root = element-web; }; }; }; }