diff options
-rw-r--r-- | nixos/doc/manual/from_md/release-notes/rl-2205.section.xml | 110 | ||||
-rw-r--r-- | nixos/doc/manual/release-notes/rl-2205.section.md | 89 | ||||
-rw-r--r-- | nixos/modules/module-list.nix | 2 | ||||
-rw-r--r-- | nixos/modules/services/matrix/matrix-synapse-log_config.yaml (renamed from nixos/modules/services/misc/matrix-synapse-log_config.yaml) | 0 | ||||
-rw-r--r-- | nixos/modules/services/matrix/matrix-synapse.nix | 773 | ||||
-rw-r--r-- | nixos/modules/services/matrix/matrix-synapse.xml (renamed from nixos/modules/services/misc/matrix-synapse.xml) | 35 | ||||
-rw-r--r-- | nixos/modules/services/misc/matrix-synapse.nix | 844 | ||||
-rw-r--r-- | nixos/tests/matrix-appservice-irc.nix | 46 | ||||
-rw-r--r-- | nixos/tests/matrix-synapse.nix | 64 | ||||
-rw-r--r-- | nixos/tests/matrix/mjolnir.nix | 43 | ||||
-rw-r--r-- | nixos/tests/matrix/pantalaimon.nix | 29 |
11 files changed, 1112 insertions, 923 deletions
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml index 2d8279725ff..4f4a5a3394e 100644 --- a/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml +++ b/nixos/doc/manual/from_md/release-notes/rl-2205.section.xml @@ -390,6 +390,116 @@ </listitem> <listitem> <para> + The <literal>matrix-synapse</literal> service + (<literal>services.matrix-synapse</literal>) has been + converted to use the <literal>settings</literal> option + defined in RFC42. This means that options that are part of + your <literal>homeserver.yaml</literal> configuration, and + that were specified at the top-level of the module + (<literal>services.matrix-synapse</literal>) now need to be + moved into + <literal>services.matrix-synapse.settings</literal>. And while + not all options you may use are defined in there, they are + still supported, because you can set arbitrary values in this + freeform type. + </para> + <para> + An example to make the required migration clearer: + </para> + <para> + Before: + </para> + <programlisting language="bash"> +{ + services.matrix-synapse = { + enable = true; + + server_name = "example.com"; + public_baseurl = "https://example.com:8448"; + + enable_registration = false; + registration_shared_secret = "xohshaeyui8jic7uutuDogahkee3aehuaf6ei3Xouz4iicie5thie6nohNahceut"; + macaroon_secret_key = "xoo8eder9seivukaiPh1cheikohquuw8Yooreid0The4aifahth3Ou0aiShaiz4l"; + + tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem"; + tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem"; + + listeners = [ { + port = 8448; + bind_address = ""; + type = "http"; + tls = true; + resources = [ { + names = [ "client" ]; + compress = true; + } { + names = [ "federation" ]; + compress = false; + } ]; + } ]; + + }; +} +</programlisting> + <para> + After: + </para> + <programlisting language="bash"> +{ + services.matrix-synapse = { + enable = true; + + # this attribute set holds all values that go into your homeserver.yaml configuration + # See https://github.com/matrix-org/synapse/blob/develop/docs/sample_config.yaml for + # possible values. + settings = { + server_name = "example.com"; + public_baseurl = "https://example.com:8448"; + + enable_registration = false; + # pass `registration_shared_secret` and `macaroon_secret_key` via `extraConfigFiles` instead + + tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem"; + tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem"; + + listeners = [ { + port = 8448; + bind_address = [ + "::" + "0.0.0.0" + ]; + type = "http"; + tls = true; + resources = [ { + names = [ "client" ]; + compress = true; + } { + names = [ "federation" ]; + compress = false; + } ]; + } ]; + }; + + extraConfigFiles = [ + /run/keys/matrix-synapse/secrets.yaml + ]; + }; +} +</programlisting> + <para> + The secrets in your original config should be migrated into a + YAML file that is included via + <literal>extraConfigFiles</literal>. + </para> + <para> + Additionally a few option defaults have been synced up with + upstream default values, for example the + <literal>max_upload_size</literal> grew from + <literal>10M</literal> to <literal>50M</literal>. + </para> + </listitem> + <listitem> + <para> The MoinMoin wiki engine (<literal>services.moinmoin</literal>) has been removed, because Python 2 is being retired from nixpkgs. diff --git a/nixos/doc/manual/release-notes/rl-2205.section.md b/nixos/doc/manual/release-notes/rl-2205.section.md index 51d7f009606..c4281561f16 100644 --- a/nixos/doc/manual/release-notes/rl-2205.section.md +++ b/nixos/doc/manual/release-notes/rl-2205.section.md @@ -128,6 +128,95 @@ In addition to numerous new and upgraded packages, this release has the followin - The `mailpile` email webclient (`services.mailpile`) has been removed due to its reliance on python2. +- The `matrix-synapse` service (`services.matrix-synapse`) has been converted to use the `settings` option defined in RFC42. + This means that options that are part of your `homeserver.yaml` configuration, and that were specified at the top-level of the + module (`services.matrix-synapse`) now need to be moved into `services.matrix-synapse.settings`. And while not all options you + may use are defined in there, they are still supported, because you can set arbitrary values in this freeform type. + + An example to make the required migration clearer: + + Before: + ```nix + { + services.matrix-synapse = { + enable = true; + + server_name = "example.com"; + public_baseurl = "https://example.com:8448"; + + enable_registration = false; + registration_shared_secret = "xohshaeyui8jic7uutuDogahkee3aehuaf6ei3Xouz4iicie5thie6nohNahceut"; + macaroon_secret_key = "xoo8eder9seivukaiPh1cheikohquuw8Yooreid0The4aifahth3Ou0aiShaiz4l"; + + tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem"; + tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem"; + + listeners = [ { + port = 8448; + bind_address = ""; + type = "http"; + tls = true; + resources = [ { + names = [ "client" ]; + compress = true; + } { + names = [ "federation" ]; + compress = false; + } ]; + } ]; + + }; + } + ``` + + After: + ```nix + { + services.matrix-synapse = { + enable = true; + + # this attribute set holds all values that go into your homeserver.yaml configuration + # See https://github.com/matrix-org/synapse/blob/develop/docs/sample_config.yaml for + # possible values. + settings = { + server_name = "example.com"; + public_baseurl = "https://example.com:8448"; + + enable_registration = false; + # pass `registration_shared_secret` and `macaroon_secret_key` via `extraConfigFiles` instead + + tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem"; + tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem"; + + listeners = [ { + port = 8448; + bind_address = [ + "::" + "0.0.0.0" + ]; + type = "http"; + tls = true; + resources = [ { + names = [ "client" ]; + compress = true; + } { + names = [ "federation" ]; + compress = false; + } ]; + } ]; + }; + + extraConfigFiles = [ + /run/keys/matrix-synapse/secrets.yaml + ]; + }; + } + ``` + + The secrets in your original config should be migrated into a YAML file that is included via `extraConfigFiles`. + + Additionally a few option defaults have been synced up with upstream default values, for example the `max_upload_size` grew from `10M` to `50M`. + - The MoinMoin wiki engine (`services.moinmoin`) has been removed, because Python 2 is being retired from nixpkgs. - The `wafHook` hook now honors `NIX_BUILD_CORES` when `enableParallelBuilding` is not set explicitly. Packages can restore the old behaviour by setting `enableParallelBuilding=false`. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 7bce1119d73..1d2faddfff2 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -499,6 +499,7 @@ ./services/mail/roundcube.nix ./services/mail/sympa.nix ./services/mail/nullmailer.nix + ./services/matrix/matrix-synapse.nix ./services/matrix/mjolnir.nix ./services/matrix/pantalaimon.nix ./services/misc/ananicy.nix @@ -565,7 +566,6 @@ ./services/misc/matrix-appservice-discord.nix ./services/misc/matrix-appservice-irc.nix ./services/misc/matrix-conduit.nix - ./services/misc/matrix-synapse.nix ./services/misc/mautrix-facebook.nix ./services/misc/mautrix-telegram.nix ./services/misc/mbpfan.nix diff --git a/nixos/modules/services/misc/matrix-synapse-log_config.yaml b/nixos/modules/services/matrix/matrix-synapse-log_config.yaml index d85bdd1208f..d85bdd1208f 100644 --- a/nixos/modules/services/misc/matrix-synapse-log_config.yaml +++ b/nixos/modules/services/matrix/matrix-synapse-log_config.yaml diff --git a/nixos/modules/services/matrix/matrix-synapse.nix b/nixos/modules/services/matrix/matrix-synapse.nix new file mode 100644 index 00000000000..c4d14dbd547 --- /dev/null +++ b/nixos/modules/services/matrix/matrix-synapse.nix @@ -0,0 +1,773 @@ +{ config, lib, options, pkgs, ... }: + +with lib; + +let + cfg = config.services.matrix-synapse; + format = pkgs.formats.yaml {}; + + # remove null values from the final configuration + finalSettings = lib.filterAttrsRecursive (_: v: v != null) cfg.settings; + configFile = format.generate "homeserver.yaml" finalSettings; + logConfigFile = format.generate "log_config.yaml" cfg.logConfig; + + pluginsEnv = cfg.package.python.buildEnv.override { + extraLibs = cfg.plugins; + }; + + usePostgresql = cfg.settings.database.name == "psycopg2"; + hasLocalPostgresDB = let args = cfg.settings.database.args; in + usePostgresql && (!(args ? host) || (elem args.host [ "localhost" "127.0.0.1" "::1" ])); + + registerNewMatrixUser = + let + isIpv6 = x: lib.length (lib.splitString ":" x) > 1; + listener = + lib.findFirst ( + listener: lib.any ( + resource: lib.any ( + name: name == "client" + ) resource.names + ) listener.resources + ) (lib.last cfg.settings.listeners) cfg.settings.listeners; + # FIXME: Handle cases with missing client listener properly, + # don't rely on lib.last, this will not work. + + # add a tail, so that without any bind_addresses we still have a useable address + bindAddress = head (listener.bind_addresses ++ [ "127.0.0.1" ]); + listenerProtocol = if listener.tls + then "https" + else "http"; + in + pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" '' + exec ${cfg.package}/bin/register_new_matrix_user \ + $@ \ + ${lib.concatMapStringsSep " " (x: "-c ${x}") ([ configFile ] ++ cfg.extraConfigFiles)} \ + "${listenerProtocol}://${ + if (isIpv6 bindAddress) then + "[${bindAddress}]" + else + "${bindAddress}" + }:${builtins.toString listener.port}/" + ''; +in { + + imports = [ + + (mkRemovedOptionModule [ "services" "matrix-synapse" "trusted_third_party_id_servers" ] '' + The `trusted_third_party_id_servers` option as been removed in `matrix-synapse` v1.4.0 + as the behavior is now obsolete. + '') + (mkRemovedOptionModule [ "services" "matrix-synapse" "create_local_database" ] '' + Database configuration must be done manually. An exemplary setup is demonstrated in + <nixpkgs/nixos/tests/matrix-synapse.nix> + '') + (mkRemovedOptionModule [ "services" "matrix-synapse" "web_client" ] "") + (mkRemovedOptionModule [ "services" "matrix-synapse" "room_invite_state_types" ] '' + You may add additional event types via + `services.matrix-synapse.room_prejoin_state.additional_event_types` and + disable the default events via + `services.matrix-synapse.room_prejoin_state.disable_default_event_types`. + '') + + # options that don't exist in synapse anymore + (mkRemovedOptionModule [ "services" "matrix-synapse" "bind_host" ] "Use listener settings instead." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "bind_port" ] "Use listener settings instead." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "expire_access_tokens" ] "" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "no_tls" ] "It is no longer supported by synapse." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "tls_dh_param_path" ] "It was removed from synapse." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "unsecure_port" ] "Use settings.listeners instead." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "user_creation_max_duration" ] "It is no longer supported by synapse." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "verbose" ] "Use a log config instead." ) + + # options that were moved into rfc42 style settigns + (mkRemovedOptionModule [ "services" "matrix-synapse" "app_service_config_files" ] "Use settings.app_service_config_Files instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "database_args" ] "Use settings.database.args instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "database_name" ] "Use settings.database.args.database instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "database_type" ] "Use settings.database.name instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "database_user" ] "Use settings.database.args.user instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "dynamic_thumbnails" ] "Use settings.dynamic_thumbnails instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "enable_metrics" ] "Use settings.enable_metrics instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "enable_registration" ] "Use settings.enable_registration instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "extraConfig" ] "Use settings instead." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "listeners" ] "Use settings.listeners instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "logConfig" ] "Use settings.log_config instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "max_image_pixels" ] "Use settings.max_image_pixels instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "max_upload_size" ] "Use settings.max_upload_size instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "presence" "enabled" ] "Use settings.presence.enabled instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "public_baseurl" ] "Use settings.public_baseurl instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "report_stats" ] "Use settings.report_stats instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "server_name" ] "Use settings.server_name instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "servers" ] "Use settings.trusted_key_servers instead." ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "tls_certificate_path" ] "Use settings.tls_certificate_path instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "tls_private_key_path" ] "Use settings.tls_private_key_path instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "turn_shared_secret" ] "Use settings.turn_shared_secret instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "turn_uris" ] "Use settings.turn_uris instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "turn_user_lifetime" ] "Use settings.turn_user_lifetime instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_enabled" ] "Use settings.url_preview_enabled instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_ip_range_blacklist" ] "Use settings.url_preview_ip_range_blacklist instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_ip_range_whitelist" ] "Use settings.url_preview_ip_range_whitelist instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_url_blacklist" ] "Use settings.url_preview_url_blacklist instead" ) + + # options that are too specific to mention them explicitly in settings + (mkRemovedOptionModule [ "services" "matrix-synapse" "account_threepid_delegates" "email" ] "Use settings.account_threepid_delegates.email instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "account_threepid_delegates" "msisdn" ] "Use settings.account_threepid_delegates.msisdn instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "allow_guest_access" ] "Use settings.allow_guest_access instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "bcrypt_rounds" ] "Use settings.bcrypt_rounds instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "enable_registration_captcha" ] "Use settings.enable_registration_captcha instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "event_cache_size" ] "Use settings.event_cache_size instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_concurrent" ] "Use settings.rc_federation.concurrent instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_reject_limit" ] "Use settings.rc_federation.reject_limit instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_sleep_delay" ] "Use settings.rc_federation.sleep_delay instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_sleep_limit" ] "Use settings.rc_federation.sleep_limit instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_window_size" ] "Use settings.rc_federation.window_size instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "key_refresh_interval" ] "Use settings.key_refresh_interval instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "rc_messages_burst_count" ] "Use settings.rc_messages.burst_count instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "rc_messages_per_second" ] "Use settings.rc_messages.per_second instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "recaptcha_private_key" ] "Use settings.recaptcha_private_key instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "recaptcha_public_key" ] "Use settings.recaptcha_public_key instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "redaction_retention_period" ] "Use settings.redaction_retention_period instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "room_prejoin_state" "additional_event_types" ] "Use settings.room_prejoin_state.additional_event_types instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "room_prejoin_state" "disable_default_event_types" ] "Use settings.room_prejoin-state.disable_default_event_types instead" ) + + # Options that should be passed via extraConfigFiles, so they are not persisted into the nix store + (mkRemovedOptionModule [ "services" "matrix-synapse" "macaroon_secret_key" ] "Pass this value via extraConfigFiles instead" ) + (mkRemovedOptionModule [ "services" "matrix-synapse" "registration_shared_secret" ] "Pass this value via extraConfigFiles instead" ) + + ]; + + options = { + services.matrix-synapse = { + enable = mkEnableOption "matrix.org synapse"; + + configFile = mkOption { + type = types.str; + readOnly = true; + description = '' + Path to the configuration file on the target system. Useful to configure e.g. workers + that also need this. + ''; + }; + + package = mkOption { + type = types.package; + default = pkgs.matrix-synapse; + defaultText = literalExpression "pkgs.matrix-synapse"; + description = '' + Overridable attribute of the matrix synapse server package to use. + ''; + }; + + plugins = mkOption { + type = types.listOf types.package; + default = [ ]; + example = literalExpression '' + with config.services.matrix-synapse.package.plugins; [ + matrix-synapse-ldap3 + matrix-synapse-pam + ]; + ''; + description = '' + List of additional Matrix plugins to make available. + ''; + }; + + withJemalloc = mkOption { + type = types.bool; + default = false; + description = '' + Whether to preload jemalloc to reduce memory fragmentation and overall usage. + ''; + }; + + dataDir = mkOption { + type = types.str; + default = "/var/lib/matrix-synapse"; + description = '' + The directory where matrix-synapse stores its stateful data such as + certificates, media and uploads. + ''; + }; + + settings = mkOption { + default = {}; + description = '' + The primary synapse configuration. See the + <link xlink:href="https://github.com/matrix-org/synapse/blob/v${cfg.package.version}/docs/sample_config.yaml">sample configuration</link> + for possible values. + + Secrets should be passed in by using the <literal>extraConfigFiles</literal> option. + ''; + type = with types; submodule { + freeformType = format.type; + options = { + # This is a reduced set of popular options and defaults + # Do not add every available option here, they can be specified + # by the user at their own discretion. This is a freeform type! + + server_name = mkOption { + type = types.str; + example = "example.com"; + default = config.networking.hostName; + defaultText = literalExpression "config.networking.hostName"; + description = '' + The domain name of the server, with optional explicit port. + This is used by remote servers to look up the server address. + This is also the last part of your UserID. + + The server_name cannot be changed later so it is important to configure this correctly before you start Synapse. + ''; + }; + + enable_registration = mkOption { + type = types.bool; + default = false; + description = '' + Enable registration for new users. + ''; + }; + + registration_shared_secret = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + If set, allows registration by anyone who also has the shared + secret, even if registration is otherwise disabled. + + Secrets should be passed in via <literal>extraConfigFiles</literal>! + ''; + }; + + macaroon_secret_key = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Secret key for authentication tokens. If none is specified, + the registration_shared_secret is used, if one is given; otherwise, + a secret key is derived from the signing key. + + Secrets should be passed in via <literal>extraConfigFiles</literal>! + ''; + }; + + enable_metrics = mkOption { + type = types.bool; + default = false; + description = '' + Enable collection and rendering of performance metrics + ''; + }; + + report_stats = mkOption { + type = types.bool; + default = false; + description = '' + Whether or not to report anonymized homeserver usage statistics. + ''; + }; + + signing_key_path = mkOption { + type = types.path; + default = "${cfg.dataDir}/homeserver.signing.key"; + description = '' + Path to the signing key to sign messages with. + ''; + }; + + pid_file = mkOption { + type = types.path; + default = "/run/matrix-synapse.pid"; + readOnly = true; + description = '' + The file to store the PID in. + ''; + }; + + log_config = mkOption { + type = types.path; + default = ./matrix-synapse-log_config.yaml; + description = '' + The file that holds the logging configuration. + ''; + }; + + media_store_path = mkOption { + type = types.path; + default = if lib.versionAtLeast config.system.stateVersion "22.05" + then "${cfg.dataDir}/media_store" + else "${cfg.dataDir}/media"; + description = '' + Directory where uploaded images and attachments are stored. + ''; + }; + + public_baseurl = mkOption { + type = types.nullOr types.str; + default = null; + example = "https://example.com:8448/"; + description = '' + The public-facing base URL for the client API (not including _matrix/...) + ''; + }; + + tls_certificate_path = mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/lib/acme/example.com/fullchain.pem"; + description = '' + PEM encoded X509 certificate for TLS. + You can replace the self-signed certificate that synapse + autogenerates on launch with your own SSL certificate + key pair + if you like. Any required intermediary certificates can be + appended after the primary certificate in hierarchical order. + ''; + }; + + tls_private_key_path = mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/lib/acme/example.com/key.pem"; + description = '' + PEM encoded private key for TLS. Specify null if synapse is not + speaking TLS directly. + ''; + }; + + presence.enabled = mkOption { + type = types.bool; + default = true; + example = false; + description = '' + Whether to enable presence tracking. + + Presence tracking allows users to see the state (e.g online/offline) + of other local and remote users. + ''; + }; + + listeners = mkOption { + type = types.listOf (types.submodule { + options = { + port = mkOption { + type = types.port; + example = 8448; + description = '' + The port to listen for HTTP(S) requests on. + ''; + }; + + bind_addresses = mkOption { + type = types.listOf types.str; + default = [ + "::1" + "127.0.0.1" + ]; + example = literalExpression '' + [ + "::" + "0.0.0.0" + ] + ''; + description = '' + IP addresses to bind the listener to. + ''; + }; + + type = mkOption { + type = types.enum [ + "http" + "manhole" + "metrics" + "replication" + ]; + default = "http"; + example = "metrics"; + description = '' + The type of the listener, usually http. + ''; + }; + + tls = mkOption { + type = types.bool; + default = true; + example = false; + description = '' + Whether to enable TLS on the listener socket. + ''; + }; + + x_forwarded = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Use the X-Forwarded-For (XFF) header as the client IP and not the + actual client IP. + ''; + }; + + resources = mkOption { + type = types.listOf (types.submodule { + options = { + names = mkOption { + type = types.listOf (types.enum [ + "client" + "consent" + "federation" + "keys" + "media" + "metrics" + "openid" + "replication" + "static" + ]); + description = '' + List of resources to host on this listener. + ''; + example = [ + "client" + ]; + }; + compress = mkOption { + type = types.bool; + description = '' + Should synapse compress HTTP responses to clients that support it? + This should be disabled if running synapse behind a load balancer + that can do automatic compression. + ''; + }; + }; + }); + description = '' + List of HTTP resources to serve on this listener. + ''; + }; + }; + }); + default = [ { + port = 8008; + bind_addresses = [ "127.0.0.1" ]; + type = "http"; + tls = false; + x_forwarded = true; + resources = [ { + names = [ "client" ]; + compress = true; + } { + names = [ "federation" ]; + compress = false; + } ]; + } ]; + description = '' + List of ports that Synapse should listen on, their purpose and their configuration. + ''; + }; + + database.name = mkOption { + type = types.enum [ + "sqlite3" + "psycopg2" + ]; + default = if versionAtLeast config.system.stateVersion "18.03" + then "psycopg2" + else "sqlite3"; + defaultText = literalExpression '' + if versionAtLeast config.system.stateVersion "18.03" + then "psycopg2" + else "sqlite3" + ''; + description = '' + The database engine name. Can be sqlite3 or psycopg2. + ''; + }; + + database.args.database = mkOption { + type = types.str; + default = { + sqlite3 = "${cfg.dataDir}/homeserver.db"; + psycopg2 = "matrix-synapse"; + }.${cfg.settings.database.name}; + defaultText = literalExpression '' + { + sqlite3 = "''${${options.services.matrix-synapse.dataDir}}/homeserver.db"; + psycopg2 = "matrix-synapse"; + }.''${${options.services.matrix-synapse.settings}.database.name}; + ''; + description = '' + Name of the database when using the psycopg2 backend, + path to the database location when using sqlite3. + ''; + }; + + database.args.user = mkOption { + type = types.nullOr types.str; + default = { + sqlite3 = null; + psycopg2 = "matrix-synapse"; + }.${cfg.settings.database.name}; + description = '' + Username to connect with psycopg2, set to null + when using sqlite3. + ''; + }; + + url_preview_enabled = mkOption { + type = types.bool; + default = true; + example = false; + description = '' + Is the preview URL API enabled? If enabled, you *must* specify an + explicit url_preview_ip_range_blacklist of IPs that the spider is + denied from accessing. + ''; + }; + + url_preview_ip_range_blacklist = mkOption { + type = types.listOf types.str; + default = [ + "10.0.0.0/8" + "100.64.0.0/10" + "127.0.0.0/8" + "169.254.0.0/16" + "172.16.0.0/12" + "192.0.0.0/24" + "192.0.2.0/24" + "192.168.0.0/16" + "192.88.99.0/24" + "198.18.0.0/15" + "198.51.100.0/24" + "2001:db8::/32" + "203.0.113.0/24" + "224.0.0.0/4" + "::1/128" + "fc00::/7" + "fe80::/10" + "fec0::/10" + "ff00::/8" + ]; + description = '' + List of IP address CIDR ranges that the URL preview spider is denied + from accessing. + ''; + }; + + url_preview_ip_range_whitelist = mkOption { + type = types.listOf types.str; + default = []; + description = '' + List of IP address CIDR ranges that the URL preview spider is allowed + to access even if they are specified in url_preview_ip_range_blacklist. + ''; + }; + + url_preview_url_blacklist = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Optional list of URL matches that the URL preview spider is + denied from accessing. + ''; + }; + + max_upload_size = mkOption { + type = types.str; + default = "50M"; + example = "100M"; + description = '' + The largest allowed upload size in bytes + ''; + }; + + max_image_pixels = mkOption { + type = types.str; + default = "32M"; + example = "64M"; + description = '' + Maximum number of pixels that will be thumbnailed + ''; + }; + + dynamic_thumbnails = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Whether to generate new thumbnails on the fly to precisely match + the resolution requested by the client. If true then whenever + a new resolution is requested by the client the server will + generate a new thumbnail. If false the server will pick a thumbnail + from a precalculated list. + ''; + }; + + turn_uris = mkOption { + type = types.listOf types.str; + default = []; + example = [ + "turn:turn.example.com:3487?transport=udp" + "turn:turn.example.com:3487?transport=tcp" + "turns:turn.example.com:5349?transport=udp" + "turns:turn.example.com:5349?transport=tcp" + ]; + description = '' + The public URIs of the TURN server to give to clients + ''; + }; + turn_shared_secret = mkOption { + type = types.str; + default = ""; + example = literalExpression '' + config.services.coturn.static-auth-secret + ''; + description = '' + The shared secret used to compute passwords for the TURN server. + + Secrets should be passed in via <literal>extraConfigFiles</literal>! + ''; + }; + + trusted_key_servers = mkOption { + type = types.listOf (types.submodule { + options = { + server_name = mkOption { + type = types.str; + example = "matrix.org"; + description = '' + Hostname of the trusted server. + ''; + }; + + verify_keys = mkOption { + type = types.nullOr (types.attrsOf types.str); + default = null; + example = literalExpression '' + { + "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; + } + ''; + description = '' + Attribute set from key id to base64 encoded public key. + + If specified synapse will check that the response is signed + by at least one of the given keys. + ''; + }; + }; + }); + default = [ { + server_name = "matrix.org"; + verify_keys = { + "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; + }; + } ]; + description = '' + The trusted servers to download signing keys from. + ''; + }; + + app_service_config_files = mkOption { + type = types.listOf types.path; + default = [ ]; + description = '' + A list of application service config file to use + ''; + }; + + }; + }; + }; + + extraConfigFiles = mkOption { + type = types.listOf types.path; + default = []; + description = '' + Extra config files to include. + + The configuration files will be included based on the command line + argument --config-path. This allows to configure secrets without + having to go through the Nix store, e.g. based on deployment keys if + NixOps is in use. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = [ + { assertion = hasLocalPostgresDB -> config.services.postgresql.enable; + message = '' + Cannot deploy matrix-synapse with a configuration for a local postgresql database + and a missing postgresql service. Since 20.03 it's mandatory to manually configure the + database (please read the thread in https://github.com/NixOS/nixpkgs/pull/80447 for + further reference). + + If you + - try to deploy a fresh synapse, you need to configure the database yourself. An example + for this can be found in <nixpkgs/nixos/tests/matrix-synapse.nix> + - update your existing matrix-synapse instance, you simply need to add `services.postgresql.enable = true` + to your configuration. + + For further information about this update, please read the release-notes of 20.03 carefully. + ''; + } + ]; + + services.matrix-synapse.configFile = configFile; + + users.users.matrix-synapse = { + group = "matrix-synapse"; + home = cfg.dataDir; + createHome = true; + shell = "${pkgs.bash}/bin/bash"; + uid = config.ids.uids.matrix-synapse; + }; + + users.groups.matrix-synapse = { + gid = config.ids.gids.matrix-synapse; + }; + + systemd.services.matrix-synapse = { + description = "Synapse Matrix homeserver"; + after = [ "network.target" ] ++ optional hasLocalPostgresDB "postgresql.service"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + ${cfg.package}/bin/synapse_homeserver \ + --config-path ${configFile} \ + --keys-directory ${cfg.dataDir} \ + --generate-keys + ''; + environment = { + PYTHONPATH = makeSearchPathOutput "lib" cfg.package.python.sitePackages [ pluginsEnv ]; + } // optionalAttrs (cfg.withJemalloc) { + LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so"; + }; + serviceConfig = { + Type = "notify"; + User = "matrix-synapse"; + Group = "matrix-synapse"; + WorkingDirectory = cfg.dataDir; + ExecStartPre = [ ("+" + (pkgs.writeShellScript "matrix-synapse-fix-permissions" '' + chown matrix-synapse:matrix-synapse ${cfg.dataDir}/homeserver.signing.key + chmod 0600 ${cfg.dataDir}/homeserver.signing.key + '')) ]; + ExecStart = '' + ${cfg.package}/bin/synapse_homeserver \ + ${ concatMapStringsSep "\n " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) } + --keys-directory ${cfg.dataDir} + ''; + ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID"; + Restart = "on-failure"; + UMask = "0077"; + }; + }; + + environment.systemPackages = [ registerNewMatrixUser ]; + }; + + meta = { + buildDocsInSandbox = false; + doc = ./matrix-synapse.xml; + maintainers = teams.matrix.members; + }; + +} diff --git a/nixos/modules/services/misc/matrix-synapse.xml b/nixos/modules/services/matrix/matrix-synapse.xml index 41a56df0f2b..cdc4b4de1a7 100644 --- a/nixos/modules/services/misc/matrix-synapse.xml +++ b/nixos/modules/services/matrix/matrix-synapse.xml @@ -115,20 +115,21 @@ in { }; services.matrix-synapse = { <link linkend="opt-services.matrix-synapse.enable">enable</link> = true; - <link linkend="opt-services.matrix-synapse.server_name">server_name</link> = config.networking.domain; - <link linkend="opt-services.matrix-synapse.listeners">listeners</link> = [ + <link linkend="opt-services.matrix-synapse.settings.server_name">server_name</link> = config.networking.domain; + <link linkend="opt-services.matrix-synapse.settings.listeners">listeners</link> = [ { - <link linkend="opt-services.matrix-synapse.listeners._.port">port</link> = 8008; - <link linkend="opt-services.matrix-synapse.listeners._.bind_address">bind_address</link> = "::1"; - <link linkend="opt-services.matrix-synapse.listeners._.type">type</link> = "http"; - <link linkend="opt-services.matrix-synapse.listeners._.tls">tls</link> = false; - <link linkend="opt-services.matrix-synapse.listeners._.x_forwarded">x_forwarded</link> = true; - <link linkend="opt-services.matrix-synapse.listeners._.resources">resources</link> = [ - { - <link linkend="opt-services.matrix-synapse.listeners._.resources._.names">names</link> = [ "client" "federation" ]; - <link linkend="opt-services.matrix-synapse.listeners._.resources._.compress">compress</link> = false; - } - ]; + <link linkend="opt-services.matrix-synapse.settings.listeners._.port">port</link> = 8008; + <link linkend="opt-services.matrix-synapse.settings.listeners._.bind_addresses">bind_address</link> = [ "::1" ]; + <link linkend="opt-services.matrix-synapse.settings.listeners._.type">type</link> = "http"; + <link linkend="opt-services.matrix-synapse.settings.listeners._.tls">tls</link> = false; + <link linkend="opt-services.matrix-synapse.settings.listeners._.x_forwarded">x_forwarded</link> = true; + <link linkend="opt-services.matrix-synapse.settings.listeners._.resources">resources</link> = [ { + <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.names">names</link> = [ "client" ]; + <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.compress">compress</link> = true; + } { + <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.names">names</link> = [ "federation" ]; + <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.compress">compress</link> = false; + } ]; } ]; }; @@ -151,11 +152,11 @@ in { <para> If you want to run a server with public registration by anybody, you can - then enable <literal><link linkend="opt-services.matrix-synapse.enable_registration">services.matrix-synapse.enable_registration</link> = + then enable <literal><link linkend="opt-services.matrix-synapse.settings.enable_registration">services.matrix-synapse.enable_registration</link> = true;</literal>. Otherwise, or you can generate a registration secret with <command>pwgen -s 64 1</command> and set it with - <option><link linkend="opt-services.matrix-synapse.registration_shared_secret">services.matrix-synapse.registration_shared_secret</link></option>. To - create a new user or admin, run the following after you have set the secret + <option><link linkend="opt-services.matrix-synapse.settings.registration_shared_secret">services.matrix-synapse.registration_shared_secret</link></option>. + To create a new user or admin, run the following after you have set the secret and have rebuilt NixOS: <screen> <prompt>$ </prompt>nix run nixpkgs.matrix-synapse @@ -170,7 +171,7 @@ Success! <literal>@your-username:example.org</literal>. Note that the registration secret ends up in the nix store and therefore is world-readable by any user on your machine, so it makes sense to only temporarily activate the - <link linkend="opt-services.matrix-synapse.registration_shared_secret">registration_shared_secret</link> + <link linkend="opt-services.matrix-synapse.settings.registration_shared_secret">registration_shared_secret</link> option until a better solution for NixOS is in place. </para> </section> diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix deleted file mode 100644 index feca4c5465f..00000000000 --- a/nixos/modules/services/misc/matrix-synapse.nix +++ /dev/null @@ -1,844 +0,0 @@ -{ config, lib, options, pkgs, ... }: - -with lib; - -let - cfg = config.services.matrix-synapse; - opt = options.services.matrix-synapse; - pg = config.services.postgresql; - usePostgresql = cfg.database_type == "psycopg2"; - logConfigFile = pkgs.writeText "log_config.yaml" cfg.logConfig; - mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${boolToString r.compress}}''; - mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${boolToString l.tls}, x_forwarded: ${boolToString l.x_forwarded}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}''; - pluginsEnv = cfg.package.python.buildEnv.override { - extraLibs = cfg.plugins; - }; - configFile = pkgs.writeText "homeserver.yaml" '' -${optionalString (cfg.tls_certificate_path != null) '' -tls_certificate_path: "${cfg.tls_certificate_path}" -''} -${optionalString (cfg.tls_private_key_path != null) '' -tls_private_key_path: "${cfg.tls_private_key_path}" -''} -${optionalString (cfg.tls_dh_params_path != null) '' -tls_dh_params_path: "${cfg.tls_dh_params_path}" -''} -no_tls: ${boolToString cfg.no_tls} -${optionalString (cfg.bind_port != null) '' -bind_port: ${toString cfg.bind_port} -''} -${optionalString (cfg.unsecure_port != null) '' -unsecure_port: ${toString cfg.unsecure_port} -''} -${optionalString (cfg.bind_host != null) '' -bind_host: "${cfg.bind_host}" -''} -server_name: "${cfg.server_name}" -pid_file: "/run/matrix-synapse.pid" -${optionalString (cfg.public_baseurl != null) '' -public_baseurl: "${cfg.public_baseurl}" -''} -listeners: [${concatStringsSep "," (map mkListener cfg.listeners)}] -database: { - name: "${cfg.database_type}", - args: { - ${concatStringsSep ",\n " ( - mapAttrsToList (n: v: "\"${n}\": ${builtins.toJSON v}") cfg.database_args - )} - } -} -event_cache_size: "${cfg.event_cache_size}" -verbose: ${cfg.verbose} -log_config: "${logConfigFile}" -rc_messages_per_second: ${cfg.rc_messages_per_second} -rc_message_burst_count: ${cfg.rc_message_burst_count} -federation_rc_window_size: ${cfg.federation_rc_window_size} -federation_rc_sleep_limit: ${cfg.federation_rc_sleep_limit} -federation_rc_sleep_delay: ${cfg.federation_rc_sleep_delay} -federation_rc_reject_limit: ${cfg.federation_rc_reject_limit} -federation_rc_concurrent: ${cfg.federation_rc_concurrent} -media_store_path: "${cfg.dataDir}/media" -uploads_path: "${cfg.dataDir}/uploads" -max_upload_size: "${cfg.max_upload_size}" -max_image_pixels: "${cfg.max_image_pixels}" -dynamic_thumbnails: ${boolToString cfg.dynamic_thumbnails} -url_preview_enabled: ${boolToString cfg.url_preview_enabled} -${optionalString (cfg.url_preview_enabled == true) '' -url_preview_ip_range_blacklist: ${builtins.toJSON cfg.url_preview_ip_range_blacklist} -url_preview_ip_range_whitelist: ${builtins.toJSON cfg.url_preview_ip_range_whitelist} -url_preview_url_blacklist: ${builtins.toJSON cfg.url_preview_url_blacklist} -''} -recaptcha_private_key: "${cfg.recaptcha_private_key}" -recaptcha_public_key: "${cfg.recaptcha_public_key}" -enable_registration_captcha: ${boolToString cfg.enable_registration_captcha} -turn_uris: ${builtins.toJSON cfg.turn_uris} -turn_shared_secret: "${cfg.turn_shared_secret}" -enable_registration: ${boolToString cfg.enable_registration} -${optionalString (cfg.registration_shared_secret != null) '' -registration_shared_secret: "${cfg.registration_shared_secret}" -''} -recaptcha_siteverify_api: "https://www.google.com/recaptcha/api/siteverify" -turn_user_lifetime: "${cfg.turn_user_lifetime}" -user_creation_max_duration: ${cfg.user_creation_max_duration} -bcrypt_rounds: ${cfg.bcrypt_rounds} -allow_guest_access: ${boolToString cfg.allow_guest_access} - -account_threepid_delegates: - ${optionalString (cfg.account_threepid_delegates.email != null) "email: ${cfg.account_threepid_delegates.email}"} - ${optionalString (cfg.account_threepid_delegates.msisdn != null) "msisdn: ${cfg.account_threepid_delegates.msisdn}"} - -room_prejoin_state: - disable_default_event_types: ${boolToString cfg.room_prejoin_state.disable_default_event_types} - additional_event_types: ${builtins.toJSON cfg.room_prejoin_state.additional_event_types} -${optionalString (cfg.macaroon_secret_key != null) '' - macaroon_secret_key: "${cfg.macaroon_secret_key}" -''} -expire_access_token: ${boolToString cfg.expire_access_token} -enable_metrics: ${boolToString cfg.enable_metrics} -report_stats: ${boolToString cfg.report_stats} -signing_key_path: "${cfg.dataDir}/homeserver.signing.key" -key_refresh_interval: "${cfg.key_refresh_interval}" -perspectives: - servers: { - ${concatStringsSep "},\n" (mapAttrsToList (n: v: '' - "${n}": { - "verify_keys": { - ${concatStringsSep "},\n" (mapAttrsToList (n: v: '' - "${n}": { - "key": "${v}" - }'') v)} - } - '') cfg.servers)} - } - } -redaction_retention_period: ${toString cfg.redaction_retention_period} -app_service_config_files: ${builtins.toJSON cfg.app_service_config_files} - -${cfg.extraConfig} -''; - - hasLocalPostgresDB = let args = cfg.database_args; in - usePostgresql && (!(args ? host) || (elem args.host [ "localhost" "127.0.0.1" "::1" ])); - - registerNewMatrixUser = - let - isIpv6 = x: lib.length (lib.splitString ":" x) > 1; - listener = - lib.findFirst ( - listener: lib.any ( - resource: lib.any ( - name: name == "client" - ) resource.names - ) listener.resources - ) (lib.last cfg.listeners) cfg.listeners; - in - pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" '' - exec ${cfg.package}/bin/register_new_matrix_user \ - $@ \ - ${lib.concatMapStringsSep " " (x: "-c ${x}") ([ configFile ] ++ cfg.extraConfigFiles)} \ - "${listener.type}://${ - if (isIpv6 listener.bind_address) then - "[${listener.bind_address}]" - else - "${listener.bind_address}" - }:${builtins.toString listener.port}/" - ''; -in { - options = { - services.matrix-synapse = { - enable = mkEnableOption "matrix.org synapse"; - configFile = mkOption { - type = types.str; - readOnly = true; - description = '' - Path to the configuration file on the target system. Useful to configure e.g. workers - that also need this. - ''; - }; - package = mkOption { - type = types.package; - default = pkgs.matrix-synapse; - defaultText = literalExpression "pkgs.matrix-synapse"; - description = '' - Overridable attribute of the matrix synapse server package to use. - ''; - }; - plugins = mkOption { - type = types.listOf types.package; - default = [ ]; - example = literalExpression '' - with config.services.matrix-synapse.package.plugins; [ - matrix-synapse-ldap3 - matrix-synapse-pam - ]; - ''; - description = '' - List of additional Matrix plugins to make available. - ''; - }; - withJemalloc = mkOption { - type = types.bool; - default = false; - description = '' - Whether to preload jemalloc to reduce memory fragmentation and overall usage. - ''; - }; - no_tls = mkOption { - type = types.bool; - default = false; - description = '' - Don't bind to the https port - ''; - }; - bind_port = mkOption { - type = types.nullOr types.int; - default = null; - example = 8448; - description = '' - DEPRECATED: Use listeners instead. - The port to listen for HTTPS requests on. - For when matrix traffic is sent directly to synapse. - ''; - }; - unsecure_port = mkOption { - type = types.nullOr types.int; - default = null; - example = 8008; - description = '' - DEPRECATED: Use listeners instead. - The port to listen for HTTP requests on. - For when matrix traffic passes through loadbalancer that unwraps TLS. - ''; - }; - bind_host = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - DEPRECATED: Use listeners instead. - Local interface to listen on. - The empty string will cause synapse to listen on all interfaces. - ''; - }; - tls_certificate_path = mkOption { - type = types.nullOr types.str; - default = null; - example = "/var/lib/matrix-synapse/homeserver.tls.crt"; - description = '' - PEM encoded X509 certificate for TLS. - You can replace the self-signed certificate that synapse - autogenerates on launch with your own SSL certificate + key pair - if you like. Any required intermediary certificates can be - appended after the primary certificate in hierarchical order. - ''; - }; - tls_private_key_path = mkOption { - type = types.nullOr types.str; - default = null; - example = "/var/lib/matrix-synapse/homeserver.tls.key"; - description = '' - PEM encoded private key for TLS. Specify null if synapse is not - speaking TLS directly. - ''; - }; - tls_dh_params_path = mkOption { - type = types.nullOr types.str; - default = null; - example = "/var/lib/matrix-synapse/homeserver.tls.dh"; - description = '' - PEM dh parameters for ephemeral keys - ''; - }; - server_name = mkOption { - type = types.str; - example = "example.com"; - default = config.networking.hostName; - defaultText = literalExpression "config.networking.hostName"; - description = '' - The domain name of the server, with optional explicit port. - This is used by remote servers to look up the server address. - This is also the last part of your UserID. - - The server_name cannot be changed later so it is important to configure this correctly before you start Synapse. - ''; - }; - public_baseurl = mkOption { - type = types.nullOr types.str; - default = null; - example = "https://example.com:8448/"; - description = '' - The public-facing base URL for the client API (not including _matrix/...) - ''; - }; - listeners = mkOption { - type = types.listOf (types.submodule { - options = { - port = mkOption { - type = types.port; - example = 8448; - description = '' - The port to listen for HTTP(S) requests on. - ''; - }; - bind_address = mkOption { - type = types.str; - default = ""; - example = "203.0.113.42"; - description = '' - Local interface to listen on. - The empty string will cause synapse to listen on all interfaces. - ''; - }; - type = mkOption { - type = types.str; - default = "http"; - description = '' - Type of listener. - ''; - }; - tls = mkOption { - type = types.bool; - default = true; - description = '' - Whether to listen for HTTPS connections rather than HTTP. - ''; - }; - x_forwarded = mkOption { - type = types.bool; - default = false; - description = '' - Use the X-Forwarded-For (XFF) header as the client IP and not the - actual client IP. - ''; - }; - resources = mkOption { - type = types.listOf (types.submodule { - options = { - names = mkOption { - type = types.listOf types.str; - description = '' - List of resources to host on this listener. - ''; - example = ["client" "federation"]; - }; - compress = mkOption { - type = types.bool; - description = '' - Should synapse compress HTTP responses to clients that support it? - This should be disabled if running synapse behind a load balancer - that can do automatic compression. - ''; - }; - }; - }); - description = '' - List of HTTP resources to serve on this listener. - ''; - }; - }; - }); - default = [{ - port = 8448; - bind_address = ""; - type = "http"; - tls = true; - x_forwarded = false; - resources = [ - { names = ["client"]; compress = true; } - { names = ["federation"]; compress = false; } - ]; - }]; - description = '' - List of ports that Synapse should listen on, their purpose and their configuration. - ''; - }; - verbose = mkOption { - type = types.str; - default = "0"; - description = "Logging verbosity level."; - }; - rc_messages_per_second = mkOption { - type = types.str; - default = "0.2"; - description = "Number of messages a client can send per second"; - }; - rc_message_burst_count = mkOption { - type = types.str; - default = "10.0"; - description = "Number of message a client can send before being throttled"; - }; - federation_rc_window_size = mkOption { - type = types.str; - default = "1000"; - description = "The federation window size in milliseconds"; - }; - federation_rc_sleep_limit = mkOption { - type = types.str; - default = "10"; - description = '' - The number of federation requests from a single server in a window - before the server will delay processing the request. - ''; - }; - federation_rc_sleep_delay = mkOption { - type = types.str; - default = "500"; - description = '' - The duration in milliseconds to delay processing events from - remote servers by if they go over the sleep limit. - ''; - }; - federation_rc_reject_limit = mkOption { - type = types.str; - default = "50"; - description = '' - The maximum number of concurrent federation requests allowed - from a single server - ''; - }; - federation_rc_concurrent = mkOption { - type = types.str; - default = "3"; - description = "The number of federation requests to concurrently process from a single server"; - }; - database_type = mkOption { - type = types.enum [ "sqlite3" "psycopg2" ]; - default = if versionAtLeast config.system.stateVersion "18.03" - then "psycopg2" - else "sqlite3"; - defaultText = literalExpression '' - if versionAtLeast config.system.stateVersion "18.03" - then "psycopg2" - else "sqlite3" - ''; - description = '' - The database engine name. Can be sqlite or psycopg2. - ''; - }; - database_name = mkOption { - type = types.str; - default = "matrix-synapse"; - description = "Database name."; - }; - database_user = mkOption { - type = types.str; - default = "matrix-synapse"; - description = "Database user name."; - }; - database_args = mkOption { - type = types.attrs; - default = { - sqlite3 = { database = "${cfg.dataDir}/homeserver.db"; }; - psycopg2 = { - user = cfg.database_user; - database = cfg.database_name; - }; - }.${cfg.database_type}; - defaultText = literalDocBook '' - <variablelist> - <varlistentry> - <term>using sqlite3</term> - <listitem> - <programlisting> - { database = "''${config.${opt.dataDir}}/homeserver.db"; } - </programlisting> - </listitem> - </varlistentry> - <varlistentry> - <term>using psycopg2</term> - <listitem> - <programlisting> - psycopg2 = { - user = config.${opt.database_user}; - database = config.${opt.database_name}; - } - </programlisting> - </listitem> - </varlistentry> - </variablelist> - ''; - description = '' - Arguments to pass to the engine. - ''; - }; - event_cache_size = mkOption { - type = types.str; - default = "10K"; - description = "Number of events to cache in memory."; - }; - url_preview_enabled = mkOption { - type = types.bool; - default = false; - description = '' - Is the preview URL API enabled? If enabled, you *must* specify an - explicit url_preview_ip_range_blacklist of IPs that the spider is - denied from accessing. - ''; - }; - url_preview_ip_range_blacklist = mkOption { - type = types.listOf types.str; - default = [ - "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" - ]; - description = '' - List of IP address CIDR ranges that the URL preview spider is denied - from accessing. - ''; - }; - url_preview_ip_range_whitelist = mkOption { - type = types.listOf types.str; - default = []; - description = '' - List of IP address CIDR ranges that the URL preview spider is allowed - to access even if they are specified in - url_preview_ip_range_blacklist. - ''; - }; - url_preview_url_blacklist = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Optional list of URL matches that the URL preview spider is - denied from accessing. - ''; - }; - recaptcha_private_key = mkOption { - type = types.str; - default = ""; - description = '' - This Home Server's ReCAPTCHA private key. - ''; - }; - recaptcha_public_key = mkOption { - type = types.str; - default = ""; - description = '' - This Home Server's ReCAPTCHA public key. - ''; - }; - enable_registration_captcha = mkOption { - type = types.bool; - default = false; - description = '' - Enables ReCaptcha checks when registering, preventing signup - unless a captcha is answered. Requires a valid ReCaptcha - public/private key. - ''; - }; - turn_uris = mkOption { - type = types.listOf types.str; - default = []; - description = '' - The public URIs of the TURN server to give to clients - ''; - }; - turn_shared_secret = mkOption { - type = types.str; - default = ""; - description = '' - The shared secret used to compute passwords for the TURN server - ''; - }; - turn_user_lifetime = mkOption { - type = types.str; - default = "1h"; - description = "How long generated TURN credentials last"; - }; - enable_registration = mkOption { - type = types.bool; - default = false; - description = '' - Enable registration for new users. - ''; - }; - registration_shared_secret = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - If set, allows registration by anyone who also has the shared - secret, even if registration is otherwise disabled. - ''; - }; - enable_metrics = mkOption { - type = types.bool; - default = false; - description = '' - Enable collection and rendering of performance metrics - ''; - }; - report_stats = mkOption { - type = types.bool; - default = false; - description = ""; - }; - servers = mkOption { - type = types.attrsOf (types.attrsOf types.str); - default = { - "matrix.org" = { - "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; - }; - }; - description = '' - The trusted servers to download signing keys from. - ''; - }; - max_upload_size = mkOption { - type = types.str; - default = "10M"; - description = "The largest allowed upload size in bytes"; - }; - max_image_pixels = mkOption { - type = types.str; - default = "32M"; - description = "Maximum number of pixels that will be thumbnailed"; - }; - dynamic_thumbnails = mkOption { - type = types.bool; - default = false; - description = '' - Whether to generate new thumbnails on the fly to precisely match - the resolution requested by the client. If true then whenever - a new resolution is requested by the client the server will - generate a new thumbnail. If false the server will pick a thumbnail - from a precalculated list. - ''; - }; - user_creation_max_duration = mkOption { - type = types.str; - default = "1209600000"; - description = '' - Sets the expiry for the short term user creation in - milliseconds. The default value is two weeks. - ''; - }; - bcrypt_rounds = mkOption { - type = types.str; - default = "12"; - description = '' - Set the number of bcrypt rounds used to generate password hash. - Larger numbers increase the work factor needed to generate the hash. - ''; - }; - allow_guest_access = mkOption { - type = types.bool; - default = false; - description = '' - Allows users to register as guests without a password/email/etc, and - participate in rooms hosted on this server which have been made - accessible to anonymous users. - ''; - }; - account_threepid_delegates.email = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Delegate email sending to https://example.org - ''; - }; - account_threepid_delegates.msisdn = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Delegate SMS sending to this local process (https://localhost:8090) - ''; - }; - room_prejoin_state.additional_event_types = mkOption { - default = []; - type = types.listOf types.str; - description = '' - Additional events to share with users who received an invite. - ''; - }; - room_prejoin_state.disable_default_event_types = mkOption { - default = false; - type = types.bool; - description = '' - Whether to disable the default state-event types for users invited to a room. - These are: - - <itemizedlist> - <listitem><para>m.room.join_rules</para></listitem> - <listitem><para>m.room.canonical_alias</para></listitem> - <listitem><para>m.room.avatar</para></listitem> - <listitem><para>m.room.encryption</para></listitem> - <listitem><para>m.room.name</para></listitem> - <listitem><para>m.room.create</para></listitem> - </itemizedlist> - ''; - }; - macaroon_secret_key = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Secret key for authentication tokens - ''; - }; - expire_access_token = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable access token expiration. - ''; - }; - key_refresh_interval = mkOption { - type = types.str; - default = "1d"; - description = '' - How long key response published by this server is valid for. - Used to set the valid_until_ts in /key/v2 APIs. - Determines how quickly servers will query to check which keys - are still valid. - ''; - }; - app_service_config_files = mkOption { - type = types.listOf types.path; - default = [ ]; - description = '' - A list of application service config file to use - ''; - }; - redaction_retention_period = mkOption { - type = types.int; - default = 7; - description = '' - How long to keep redacted events in unredacted form in the database. - ''; - }; - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Extra config options for matrix-synapse. - ''; - }; - extraConfigFiles = mkOption { - type = types.listOf types.path; - default = []; - description = '' - Extra config files to include. - - The configuration files will be included based on the command line - argument --config-path. This allows to configure secrets without - having to go through the Nix store, e.g. based on deployment keys if - NixOPS is in use. - ''; - }; - logConfig = mkOption { - type = types.lines; - default = readFile ./matrix-synapse-log_config.yaml; - description = '' - A yaml python logging config file - ''; - }; - dataDir = mkOption { - type = types.str; - default = "/var/lib/matrix-synapse"; - description = '' - The directory where matrix-synapse stores its stateful data such as - certificates, media and uploads. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - assertions = [ - { assertion = hasLocalPostgresDB -> config.services.postgresql.enable; - message = '' - Cannot deploy matrix-synapse with a configuration for a local postgresql database - and a missing postgresql service. Since 20.03 it's mandatory to manually configure the - database (please read the thread in https://github.com/NixOS/nixpkgs/pull/80447 for - further reference). - - If you - - try to deploy a fresh synapse, you need to configure the database yourself. An example - for this can be found in <nixpkgs/nixos/tests/matrix-synapse.nix> - - update your existing matrix-synapse instance, you simply need to add `services.postgresql.enable = true` - to your configuration. - - For further information about this update, please read the release-notes of 20.03 carefully. - ''; - } - ]; - - services.matrix-synapse.configFile = "${configFile}"; - - users.users.matrix-synapse = { - group = "matrix-synapse"; - home = cfg.dataDir; - createHome = true; - shell = "${pkgs.bash}/bin/bash"; - uid = config.ids.uids.matrix-synapse; - }; - - users.groups.matrix-synapse = { - gid = config.ids.gids.matrix-synapse; - }; - - systemd.services.matrix-synapse = { - description = "Synapse Matrix homeserver"; - after = [ "network.target" ] ++ optional hasLocalPostgresDB "postgresql.service"; - wantedBy = [ "multi-user.target" ]; - preStart = '' - ${cfg.package}/bin/synapse_homeserver \ - --config-path ${configFile} \ - --keys-directory ${cfg.dataDir} \ - --generate-keys - ''; - environment = { - PYTHONPATH = makeSearchPathOutput "lib" cfg.package.python.sitePackages [ pluginsEnv ]; - } // optionalAttrs (cfg.withJemalloc) { - LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so"; - }; - serviceConfig = { - Type = "notify"; - User = "matrix-synapse"; - Group = "matrix-synapse"; - WorkingDirectory = cfg.dataDir; - ExecStartPre = [ ("+" + (pkgs.writeShellScript "matrix-synapse-fix-permissions" '' - chown matrix-synapse:matrix-synapse ${cfg.dataDir}/homeserver.signing.key - chmod 0600 ${cfg.dataDir}/homeserver.signing.key - '')) ]; - ExecStart = '' - ${cfg.package}/bin/synapse_homeserver \ - ${ concatMapStringsSep "\n " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) } - --keys-directory ${cfg.dataDir} - ''; - ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID"; - Restart = "on-failure"; - UMask = "0077"; - }; - }; - - environment.systemPackages = [ registerNewMatrixUser ]; - }; - - imports = [ - (mkRemovedOptionModule [ "services" "matrix-synapse" "trusted_third_party_id_servers" ] '' - The `trusted_third_party_id_servers` option as been removed in `matrix-synapse` v1.4.0 - as the behavior is now obsolete. - '') - (mkRemovedOptionModule [ "services" "matrix-synapse" "create_local_database" ] '' - Database configuration must be done manually. An exemplary setup is demonstrated in - <nixpkgs/nixos/tests/matrix-synapse.nix> - '') - (mkRemovedOptionModule [ "services" "matrix-synapse" "web_client" ] "") - (mkRemovedOptionModule [ "services" "matrix-synapse" "room_invite_state_types" ] '' - You may add additional event types via - `services.matrix-synapse.room_prejoin_state.additional_event_types` and - disable the default events via - `services.matrix-synapse.room_prejoin_state.disable_default_event_types`. - '') - ]; - - meta.doc = ./matrix-synapse.xml; - meta.maintainers = teams.matrix.members; - -} diff --git a/nixos/tests/matrix-appservice-irc.nix b/nixos/tests/matrix-appservice-irc.nix index e1da410af06..d1c561f95db 100644 --- a/nixos/tests/matrix-appservice-irc.nix +++ b/nixos/tests/matrix-appservice-irc.nix @@ -1,6 +1,6 @@ import ./make-test-python.nix ({ pkgs, ... }: let - homeserverUrl = "http://homeserver:8448"; + homeserverUrl = "http://homeserver:8008"; in { name = "matrix-appservice-irc"; @@ -14,28 +14,32 @@ import ./make-test-python.nix ({ pkgs, ... }: specialisation.running.configuration = { services.matrix-synapse = { enable = true; - database_type = "sqlite3"; - app_service_config_files = [ "/registration.yml" ]; - - enable_registration = true; - - listeners = [ - # The default but tls=false - { - "bind_address" = ""; - "port" = 8448; - "resources" = [ - { "compress" = true; "names" = [ "client" ]; } - { "compress" = false; "names" = [ "federation" ]; } + settings = { + database.name = "sqlite3"; + app_service_config_files = [ "/registration.yml" ]; + + enable_registration = true; + + listeners = [ { + # The default but tls=false + bind_addresses = [ + "0.0.0.0" ]; - "tls" = false; - "type" = "http"; - "x_forwarded" = false; - } - ]; + port = 8008; + resources = [ { + "compress" = true; + "names" = [ "client" ]; + } { + "compress" = false; + "names" = [ "federation" ]; + } ]; + tls = false; + type = "http"; + } ]; + }; }; - networking.firewall.allowedTCPPorts = [ 8448 ]; + networking.firewall.allowedTCPPorts = [ 8008 ]; }; }; @@ -209,7 +213,7 @@ import ./make-test-python.nix ({ pkgs, ... }: ) homeserver.wait_for_unit("matrix-synapse.service") - homeserver.wait_for_open_port(8448) + homeserver.wait_for_open_port(8008) with subtest("ensure messages can be exchanged"): client.succeed("do_test ${homeserverUrl} >&2") diff --git a/nixos/tests/matrix-synapse.nix b/nixos/tests/matrix-synapse.nix index 21e8c24e471..1ff1e47b284 100644 --- a/nixos/tests/matrix-synapse.nix +++ b/nixos/tests/matrix-synapse.nix @@ -33,6 +33,29 @@ import ./make-test-python.nix ({ pkgs, ... } : let testUser = "alice"; testPassword = "alicealice"; testEmail = "alice@example.com"; + + listeners = [ { + port = 8448; + bind_addresses = [ + "127.0.0.1" + "::1" + ]; + type = "http"; + tls = true; + x_forwarded = false; + resources = [ { + names = [ + "client" + ]; + compress = true; + } { + names = [ + "federation" + ]; + compress = false; + } ]; + } ]; + in { name = "matrix-synapse"; @@ -48,22 +71,24 @@ in { { services.matrix-synapse = { enable = true; - database_type = "psycopg2"; - tls_certificate_path = "${cert}"; - tls_private_key_path = "${key}"; - database_args = { - password = "synapse"; + settings = { + inherit listeners; + database = { + name = "psycopg2"; + args.password = "synapse"; + }; + tls_certificate_path = "${cert}"; + tls_private_key_path = "${key}"; + registration_shared_secret = registrationSharedSecret; + public_baseurl = "https://example.com"; + email = { + smtp_host = mailerDomain; + smtp_port = 25; + require_transport_security = true; + notif_from = "matrix <matrix@${mailerDomain}>"; + app_name = "Matrix"; + }; }; - registration_shared_secret = registrationSharedSecret; - public_baseurl = "https://example.com"; - extraConfig = '' - email: - smtp_host: "${mailerDomain}" - smtp_port: 25 - require_transport_security: true - notif_from: "matrix <matrix@${mailerDomain}>" - app_name: "Matrix" - ''; }; services.postgresql = { enable = true; @@ -165,9 +190,12 @@ in { serversqlite = args: { services.matrix-synapse = { enable = true; - database_type = "sqlite3"; - tls_certificate_path = "${cert}"; - tls_private_key_path = "${key}"; + settings = { + inherit listeners; + database.name = "sqlite3"; + tls_certificate_path = "${cert}"; + tls_private_key_path = "${key}"; + }; }; }; }; diff --git a/nixos/tests/matrix/mjolnir.nix b/nixos/tests/matrix/mjolnir.nix index bb55f6f5440..54094ab9d61 100644 --- a/nixos/tests/matrix/mjolnir.nix +++ b/nixos/tests/matrix/mjolnir.nix @@ -38,26 +38,31 @@ import ../make-test-python.nix ( homeserver = { pkgs, ... }: { services.matrix-synapse = { enable = true; - database_type = "sqlite3"; - tls_certificate_path = "${cert}"; - tls_private_key_path = "${key}"; - enable_registration = true; - registration_shared_secret = "supersecret-registration"; - - listeners = [ - # The default but tls=false - { - "bind_address" = ""; - "port" = 8448; - "resources" = [ - { "compress" = true; "names" = [ "client" "webclient" ]; } - { "compress" = false; "names" = [ "federation" ]; } + settings = { + database.name = "sqlite3"; + tls_certificate_path = "${cert}"; + tls_private_key_path = "${key}"; + enable_registration = true; + registration_shared_secret = "supersecret-registration"; + + listeners = [ { + # The default but tls=false + bind_addresses = [ + "0.0.0.0" ]; - "tls" = false; - "type" = "http"; - "x_forwarded" = false; - } - ]; + port = 8448; + resources = [ { + compress = true; + names = [ "client" ]; + } { + compress = false; + names = [ "federation" ]; + } ]; + tls = false; + type = "http"; + x_forwarded = false; + } ]; + }; }; networking.firewall.allowedTCPPorts = [ 8448 ]; diff --git a/nixos/tests/matrix/pantalaimon.nix b/nixos/tests/matrix/pantalaimon.nix index fcb9904b213..1a9894dd215 100644 --- a/nixos/tests/matrix/pantalaimon.nix +++ b/nixos/tests/matrix/pantalaimon.nix @@ -47,9 +47,32 @@ import ../make-test-python.nix ( services.matrix-synapse = { enable = true; - database_type = "sqlite3"; - tls_certificate_path = "${cert}"; - tls_private_key_path = "${key}"; + settings = { + listeners = [ { + port = 8448; + bind_addresses = [ + "127.0.0.1" + "::1" + ]; + type = "http"; + tls = true; + x_forwarded = false; + resources = [ { + names = [ + "client" + ]; + compress = true; + } { + names = [ + "federation" + ]; + compress = false; + } ]; + } ]; + database.name = "sqlite3"; + tls_certificate_path = "${cert}"; + tls_private_key_path = "${key}"; + }; }; }; |