chaos-jetzt-nixfiles/services/matrix/default.nix
2023-08-31 22:03:18 +02:00

173 lines
6.5 KiB
Nix

{ lib, config, pkgs, baseDomain, ... }: let
matrixPort = 8008;
isDev = (builtins.substring 0 3 baseDomain) == "dev";
synapseDb = config.services.matrix-synapse.settings.database.args;
initSynapseDb = ''CREATE DATABASE "${synapseDb.database}" WITH OWNER "${synapseDb.user}" ENCODING "UTF8" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C";'';
in {
sops.secrets = {
"coturn_static_auth_secret".owner = "turnserver";
"synapse/signing_key" = {
owner = "matrix-synapse";
path = config.services.matrix-synapse.settings.signing_key_path;
mode = "0600";
};
"synapse/secret_config".owner = "matrix-synapse";
"synapse/registration_shared_secret".owner = "matrix-synapse";
};
services.nginx.virtualHosts = {
"chat.${baseDomain}" = {
enableACME = true;
forceSSL = true;
root = pkgs.element-web.override {
# Somewhat duplicate of the stuff in website.nix but I am
# not sure if we absolutely need to dedup this, just out of complexity perspective
conf = {
default_server_config."m.homeserver" = {
base_url = "https://matrix.${baseDomain}/";
server_name = baseDomain;
};
default_country_code = "DE";
};
};
};
"matrix.${baseDomain}" = {
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 matrixPort}";
# Forward requests for e.g. SSO and password-resets.
locations."/_synapse/client".proxyPass = "http://[::1]:${toString matrixPort}";
# # Allow public access to the synapse admin API
# # The docs advise against leaving this open to just everyone. That's why this currently is commented out
# # if admin things need to be done, it's required to SSH to the server and then direct all admin requests to
# # localhost:8008/_synapse/admin
# # Leaving that in here for when I (e1mo) wonder why calls to the admin API don't work in the future
# locations."/_synapse/admin".proxyPass = "http://[::1]:${toString matrixPort}";
};
};
services.postgresql = {
enable = true;
ensureUsers = [
{ name = synapseDb.user; }
];
};
systemd.services.postgresql = {
postStart = ''
$PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = 'matrix-synapse'" | grep -q 1 || $PSQL -tAc '${initSynapseDb}'
'';
};
security.acme.certs."turn.${baseDomain}" = {
group = "turnserver";
reloadServices = [ "coturn.service" ];
};
services.coturn = let
sslDir = config.security.acme.certs."turn.${baseDomain}".directory;
in {
enable = true;
cert = "${sslDir}/fullchain.pem";
pkey = "${sslDir}/key.pem";
static-auth-secret-file = config.sops.secrets."coturn_static_auth_secret".path;
};
# TODO: Use media storage volume on prod
services.matrix-synapse = {
enable = true;
plugins = [
pkgs.python3Packages.matrix-synapse-saml-mapper
];
settings = {
server_name = baseDomain;
public_baseurl = "https://matrix.${baseDomain}";
allow_public_rooms_over_federation = true;
enable_registration = false;
registration_shared_secret_path = config.sops.secrets."synapse/registration_shared_secret".path;
log_config = ./synapse-log_config.yaml;
database = {
name = "psycopg2";
args.database = "matrix-synapse";
};
federation_ip_range_blacklist = [
"127.0.0.0/8"
"10.0.0.0/8"
"172.16.0.0/12"
"192.168.0.0/16"
"100.64.0.0/10"
"169.254.0.0/16"
"::1/128"
"fe80::/64"
"fc00::/7"
];
admin_contact = "mailto:administration@chaos.jetzt";
url_preview_enabled = true;
media_store_path = "/mnt/synapse_media_store";
turn_uris = let
turn_base = "turn.${baseDomain}";
ct = config.services.coturn;
port = builtins.toString ct.listening-port;
tlsPort = builtins.toString ct.tls-listening-port;
in [
"turn:${turn_base}:${port}?transport=tcp"
"turn:${turn_base}:${port}?transport=udp"
"turns:${turn_base}:${tlsPort}?transport=tcp"
"turns:${turn_base}:${tlsPort}?transport=udp"
];
auto_join_rooms = builtins.map (v: "#${v}:${baseDomain}") [ "grosse_halle" "allgemein" ];
autocreate_auto_join_rooms = true;
enable_metrics = false;
user_directory = {
enabled = true;
search_all_users = true;
};
saml2_config = {
enabled = true;
sp_config.metadata.remote = [{
url = "https://sso.chaos.jetzt/auth/realms/${if isDev then "dev" else "chaos-jetzt"}/protocol/saml/descriptor";
}];
user_mapping_provider.module = "matrix_synapse_saml_mapper.SamlMappingProvider";
};
password_config.enabled = false;
};
extraConfigFiles = let
format = (pkgs.formats.yaml {}).generate;
in [
# Contains turn_shared_secret, macaroon_secret_key, and form_secret
config.sops.secrets."synapse/secret_config".path
# For our saml sso stuff we need to have additional_ressouces, but they are not possible with the NixOS module listener
(format "additional_ressources.yaml" {
listeners = [{
bind_addresses = [ "::1" "127.0.0.1" ];
port = matrixPort;
type = "http";
tls = false;
x_forwarded = true;
resources = [{
names = [ "client" "federation" ];
compress = false;
}];
additional_resources."/_matrix/saml2/pick_username".module = "matrix_synapse_saml_mapper.pick_username_resource";
}];
})
];
};
system.activationScripts."synapse-media-store-mnt".text = ''
mkdir -p ${lib.escapeShellArg config.services.matrix-synapse.settings.media_store_path}
chown matrix-synapse:matrix-synapse ${lib.escapeShellArg config.services.matrix-synapse.settings.media_store_path}
'';
systemd.services.matrix-synapse = {
unitConfig.RequiresMountsFor = [ config.services.matrix-synapse.settings.media_store_path ];
serviceConfig.ReadWritePaths = [ config.services.matrix-synapse.settings.media_store_path ];
};
}