Matrix: Difference between revisions
mNo edit summary |
Update mas config for the new upcomming fix pr #537261 |
||
| (26 intermediate revisions by 13 users not shown) | |||
| Line 3: | Line 3: | ||
This article extends the documentation in [https://nixos.org/manual/nixos/stable/#module-services-matrix NixOS manual]. | This article extends the documentation in [https://nixos.org/manual/nixos/stable/#module-services-matrix NixOS manual]. | ||
== | == Joining the community on Matrix == | ||
https://matrix.to/#/#community:nixos.org | You can read more about the different rooms on [[MatrixRooms]] and join them either from https://matrix.to/#/#community:nixos.org or directly from your client. | ||
An unofficial service provides Matrix accounts for members of the NixOS organization on GitHub: https://discourse.nixos.org/t/matrix-account-hosting-for-nix-os-hackers/14036 | |||
https://discourse.nixos.org/t/matrix-account-hosting-for-nix-os-hackers/14036 | |||
== Clients == | == Clients == | ||
| Line 15: | Line 13: | ||
=== Desktop clients === | === Desktop clients === | ||
The clients <code>element-desktop</code> [https://element.io/] and <code>fractal</code> [https://gitlab.gnome.org/World/fractal] are known to work and are kept up to date. | |||
Other clients packaged in Nixpkgs, such as <code>matrix-commander</code>, <code>neochat</code>, <code>nheko</code>, depend on the insecure <code>olm</code> library susceptible to various security vulnerabilities.[https://nvd.nist.gov/vuln/detail/CVE-2024-45191][https://nvd.nist.gov/vuln/detail/CVE-2024-45193][https://nvd.nist.gov/vuln/detail/CVE-2024-45192] | |||
If this is not a concern, the guide to [https://nixos.org/manual/nixpkgs/stable/#sec-allow-insecure install insecure packages] may be followed. | |||
==== | === Web clients === | ||
There is a web version of the client [https://element.io/ Element], <code>element-web</code> on Nixpkgs, which you can use as a regular web application. See [https://nixos.org/nixos/manual/index.html#module-services-matrix-element-web the NixOS manual entry].<syntaxhighlight lang="nixos"> | |||
{ | |||
services.nginx.enable = true; | |||
# See https://nixos.org/manual/nixos/stable/index.html#module-services-matrix-element-web | |||
services.nginx.virtualHosts."localhost" = { | |||
<syntaxhighlight lang="nix"> | listen = [{ | ||
addr = "[::1]"; | |||
port = yourPort; | |||
}]; | |||
}; | root = pkgs.element-web.override { | ||
# See https://github.com/element-hq/element-web/blob/develop/config.sample.json | |||
conf = { | |||
default_theme = "dark"; | |||
}; | |||
}; | |||
}; | |||
} | |||
</syntaxhighlight>Alternatively, you can write a script to start the web client on demand.<syntaxhighlight lang="nix"> | |||
let | |||
# port = yourPort; | |||
web-dir = pkgs.element-web.override { | |||
conf = { | |||
default_theme = "dark"; | |||
show_labs_settings = true; | |||
}; | |||
}; | |||
element-web = pkgs.writeScriptBin "element-web" '' | |||
#!${pkgs.bash}/bin/bash | |||
set -e | |||
${pkgs.python3}/bin/python3 -m http.server ${port} -b ::1 -d ${web-dir} | |||
''; | |||
in | |||
{ | |||
home.sessionPath = [ "${element-web}/bin" ]; | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == Homeservers == | ||
=== Conduit === | |||
<syntaxhighlight lang="nixos"> | |||
== | { | ||
# See https://search.nixos.org/options?channel=unstable&query=services.matrix-conduit. | |||
# and https://docs.conduit.rs/configuration.html | |||
services.matrix-conduit = { | |||
enable = true; | |||
settings.global = { | |||
# allow_registration = true; | |||
# You will need this token when creating your first account. | |||
# registration_token = "A S3CR3T TOKEN"; | |||
# server_name = yourDomainName; | |||
# port = yourPort; | |||
address = "::1"; | |||
database_backend = "rocksdb"; | |||
# See https://docs.conduit.rs/turn.html, and https://github.com/element-hq/synapse/blob/develop/docs/turn-howto.md for more details | |||
# turn_uris = [ | |||
# "turn:your.turn.url?transport=udp" | |||
# "turn:your.turn.url?transport=tcp" | |||
# ]; | |||
# turn_secret = "your secret"; | |||
}; | |||
}; | |||
} | |||
</syntaxhighlight> | |||
=== | === Synapse === | ||
[https://element-hq.github.io/synapse/latest/welcome_and_overview.html Synapse] has an associated module exposing the [https://search.nixos.org/options?query=services.matrix-synapse services.matrix-synapse.* options]. See [https://nixos.org/nixos/manual/index.html#module-services-matrix-synapse the NixOS manual entry] for a complete configuration example. | |||
==== Coturn with Synapse ==== | |||
For WebRTC calls to work when both callers are behind a NAT, you need to provide a turn server for clients to use. Here is an example configuration, inspired from [https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/roles/custom/matrix-coturn/templates/turnserver.conf.j2 this configuration file]. | |||
For WebRTC calls to work when both callers are behind a NAT, you need to provide a turn server for clients to use. Here is an example configuration, inspired from [https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/roles/matrix-coturn/templates/turnserver.conf.j2 this configuration file]. | |||
<syntaxhighlight lang="nix"> | <syntaxhighlight lang="nix"> | ||
| Line 100: | Line 139: | ||
networking.firewall = { | networking.firewall = { | ||
interfaces.enp2s0 = let | interfaces.enp2s0 = let | ||
range = with config.services.coturn; | range = with config.services.coturn; lib.singleton { | ||
from = min-port; | |||
to = max-port; | |||
}; | |||
in | in | ||
{ | { | ||
| Line 119: | Line 158: | ||
}; | }; | ||
# configure synapse to point users to coturn | # configure synapse to point users to coturn | ||
services.matrix-synapse = with config.services.coturn; { | services.matrix-synapse.settings = with config.services.coturn; { | ||
turn_uris = ["turn:${realm}:3478?transport=udp" "turn:${realm}:3478?transport=tcp"]; | turn_uris = ["turn:${realm}:3478?transport=udp" "turn:${realm}:3478?transport=tcp"]; | ||
turn_shared_secret = static-auth-secret; | turn_shared_secret = static-auth-secret; | ||
| Line 127: | Line 166: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==== Synapse with Workers ==== | |||
There's an external module to automatically set up synapse and configure nginx with workers: | There's an external module to automatically set up synapse and configure nginx with workers: | ||
https://github.com/dali99/nixos-matrix-modules | https://github.com/dali99/nixos-matrix-modules | ||
=== | ==== Synapse Admin with Caddy ==== | ||
Setting up [https://github.com/etkecc/synapse-admin Synapse Admin] with [[Caddy]] is quite easy! | |||
The example uses the newer <code>pkgs.synapse-admin-etkecc</code> which may not be what you want if you have heard of the old one which is available at: <code>pkgs.synapse-admin</code> | |||
{{File|3={ pkgs, ... }: | |||
let | |||
synapse-admin = pkgs.synapse-admin-etkecc.withConfig { | |||
restrictBaseUrl = [ | |||
"https://matrix.example.com" # Synapse domain | |||
]; | |||
}; | |||
in | |||
{ | |||
services.caddy.virtualHosts."synapse-admin.example.com".extraConfig = '' | |||
root * ${synapse-admin} | |||
file_server | |||
''; | |||
}|name=/etc/nixos/configuration.nix|lang=nix}} | |||
== Homeserver Independent == | |||
=== Livekit === | |||
In order to set up element call or for calls to work in Element X it is necessary to set up and announce livekit. To set up livekit for matrix in nixos use<syntaxhighlight lang="nix" line="1"> | |||
{ config, lib, pkgs, ... }: let | |||
keyFile = "/run/livekit.key"; | |||
in { | |||
services.livekit = { | |||
enable = true; | |||
openFirewall = true; | |||
settings.room.auto_create = false; | |||
inherit keyFile; | |||
}; | |||
services.lk-jwt-service = { | |||
enable = true; | |||
# can be on the same virtualHost as synapse | |||
livekitUrl = "wss://domain.tld/livekit/sfu"; | |||
inherit keyFile; | |||
}; | |||
# generate the key when needed | |||
systemd.services.livekit-key = { | |||
before = [ "lk-jwt-service.service" "livekit.service" ]; | |||
wantedBy = [ "multi-user.target" ]; | |||
path = with pkgs; [ livekit coreutils gawk ]; | |||
script = '' | |||
echo "Key missing, generating key" | |||
echo "lk-jwt-service: $(livekit-server generate-keys | tail -1 | awk '{print $3}')" > "${keyFile}" | |||
''; | |||
serviceConfig.Type = "oneshot"; | |||
unitConfig.ConditionPathExists = "!${keyFile}"; | |||
}; | |||
# restrict access to livekit room creation to a homeserver | |||
systemd.services.lk-jwt-service.environment.LIVEKIT_FULL_ACCESS_HOMESERVERS = "domain.tld"; | |||
services.nginx.virtualHosts."domain.tld".locations = { | |||
"^~ /livekit/jwt/" = { | |||
priority = 400; | |||
proxyPass = "http://[::1]:${toString config.services.lk-jwt-service.port}/"; | |||
}; | |||
"^~ /livekit/sfu/" = { | |||
extraConfig = '' | |||
proxy_send_timeout 120; | |||
proxy_read_timeout 120; | |||
proxy_buffering off; | |||
proxy_set_header Accept-Encoding gzip; | |||
proxy_set_header Upgrade $http_upgrade; | |||
proxy_set_header Connection "upgrade"; | |||
''; | |||
priority = 400; | |||
proxyPass = "http://[::1]:${toString config.services.livekit.settings.port}/"; | |||
proxyWebsockets = true; | |||
}; | |||
}; | |||
} | |||
</syntaxhighlight>Furthermore, it is necessary to announce the service with a <code>domain.tld/.well-known/matrix/client</code> which needs to be served as <code>Content-Type application/json</code> (calls in Element X might not work without the content-type) and contain<syntaxhighlight lang="json"> | |||
{ | |||
"m.homeserver": { | |||
"base_url": "https://domain.tld" | |||
}, | |||
"m.identity_server": { | |||
"base_url": "https://vector.im" | |||
}, | |||
"org.matrix.msc3575.proxy": { | |||
"url": "https://domain.tld" | |||
}, | |||
"org.matrix.msc4143.rtc_foci": [ | |||
{ | |||
"type": "livekit", "livekit_service_url": "https://domain.tld/livekit/jwt" | |||
} | |||
] | |||
} | |||
</syntaxhighlight> | |||
=== Matrix Authentication Service (MAS) === | |||
<blockquote>MAS module is only available since nixos 26.11</blockquote>The Matrix Authentication Service (MAS) is an OAuth 2.1 and OpenID Connect provider designed for Matrix homeservers. It is intended to become the authentication component used by Matrix homeservers implementing MSC3861. | |||
MAS provides a modern authentication layer for Matrix and enables features such as: | |||
* Single Sign-On (SSO) using external OpenID Connect providers; | |||
* Account management independent from the homeserver implementation; | |||
* Passwordless deployments relying entirely on upstream identity providers; | |||
* Future Matrix authentication features based on MSC3861 and MSC4108. | |||
MAS stores its own state in PostgreSQL and communicates with the homeserver using a shared secret. | |||
==== Basic configuration ==== | |||
A minimal configuration can be achieved with:<syntaxhighlight lang="nixos"> | |||
# MAS part | |||
services.matrix-authentication-service = { | |||
enable = true; | |||
createDatabase = true; | |||
credentials."matrix_secret" = config.age.secrets.mas_matrix_secret.path; | |||
settings = { | |||
http.public_base = "https://auth.example.com/"; | |||
http.issuer = "https://auth.example.com/"; | |||
matrix = { | |||
homeserver = "example.com"; | |||
endpoint = "http://127.0.0.1:8008/"; | |||
secret_file = "/run/credentials/matrix-authentication-service.service/matrix_secret"; | |||
}; | |||
}; | |||
}; | |||
# Synapse part | |||
services.matrix-synapse.settings = { | |||
matrix_authentication_service = { | |||
enabled = true; | |||
endpoint = "http://127.0.0.1:8089/"; | |||
secret_path = config.age.secrets.mas_matrix_secret.path; | |||
}; | |||
}; | |||
</syntaxhighlight>The following parameters are required: | |||
* <code>matrix.homeserver</code> should match the Synapse <code>server_name</code>. | |||
* <code>matrix.endpoint</code> must point to the homeserver's internal HTTP endpoint. | |||
* <code>matrix.secret_file</code> contains the shared secret used by MAS to authenticate to Synapse. | |||
** The secret should be a long, randomly generated value. For example: <code>openssl rand -hex 32</code> | |||
* <code>http.public_base</code> is the public URL used by clients to reach MAS. | |||
==== Using an upstream OpenID Connect provider ==== | |||
MAS can delegate authentication to an external OpenID Connect provider. | |||
The example below configures MAS to authenticate users through Authelia and disables the internal password database.<syntaxhighlight lang="nixos"> | |||
services.matrix-authentication-service = { | |||
enable = true; | |||
settings = { | |||
passwords.enabled = false; | |||
upstream_oauth2.providers = [ | |||
{ | |||
id = "XXXX"; | |||
human_name = "Authelia"; | |||
issuer = "https://auth.example.com"; | |||
client_id = "xxxxxxxx"; | |||
client_secret_file = "/run/credentials/matrix-authentication-service.service/xxxx"; | |||
# client_secret = "xxxxxxxx"; | |||
token_endpoint_auth_method = "client_secret_basic"; | |||
discovery_mode = "insecure"; | |||
fetch_userinfo = true; | |||
scope = "openid profile email"; | |||
claims_imports = { | |||
localpart = { | |||
action = "require"; | |||
template = "{{ user.preferred_username }}"; | |||
}; | |||
displayname = { | |||
action = "suggest"; | |||
template = "{{ user.name }}"; | |||
}; | |||
email = { | |||
action = "suggest"; | |||
template = "{{ user.email }}"; | |||
set_email_verification = "always"; | |||
}; | |||
}; | |||
} | |||
]; | |||
}; | |||
}; | |||
</syntaxhighlight>An OpenID Connect client must also be declared in Authelia:<syntaxhighlight lang="nixos"> | |||
{ | |||
client_name = "Matrix"; | |||
client_id = "<client-id>"; | |||
client_secret = "<client-secret>"; | |||
public = false; | |||
authorization_policy = "two_factor"; | |||
redirect_uris = [ | |||
"https://auth.example.com/upstream/callback/XXXX" | |||
]; | |||
scopes = [ | |||
"openid" | |||
"profile" | |||
"email" | |||
"offline_access" | |||
]; | |||
grant_types = [ | |||
"authorization_code" | |||
"refresh_token" | |||
]; | |||
response_types = [ "code" ]; | |||
} | |||
</syntaxhighlight>With this setup: | |||
* Users authenticate against Authelia. | |||
* MAS consumes the OIDC claims exposed by Authelia. | |||
* Matrix accounts are associated with the imported <code>preferred_username</code>, display name and email address. | |||
* No password is stored locally in MAS. | |||
==== Secret management ==== | |||
Secrets such as encryption keys, OIDC client secrets, and Matrix shared secrets should not be stored in the Nix store. | |||
Please use a secret management solution: [[Comparison of secret managing schemes]] | |||
See the [https://search.nixos.org/options?channel=unstable&query=matrix-authentication-service MAS configuration reference] for the complete list of available options. | |||
==== Example configuration ==== | |||
This configuration is provided for demonstration purposes only (mas+synapse+authelia with agenix for secret management): https://github.com/hatch01/flake/blob/d8e8a74b8b3df01283b79a777c46513dd78c9d10/apps/matrix/mas.nix | |||
== Application services (a.k.a. bridges) == | |||
Bridges allow you to connect Matrix to a third-party platform (like Discord, Telegram, etc.), and interact seamlessly. See [https://matrix.org/ecosystem/bridges/ here] for a list of currently supported bridges. | Bridges allow you to connect Matrix to a third-party platform (like Discord, Telegram, etc.), and interact seamlessly. See [https://matrix.org/ecosystem/bridges/ here] for a list of currently supported bridges. | ||
=== mautrix-telegram === | |||
Full configuration reference: | Full configuration reference: | ||
https://github.com/tulir/mautrix-telegram/blob/master/mautrix_telegram/example-config.yaml | https://github.com/tulir/mautrix-telegram/blob/master/mautrix_telegram/example-config.yaml | ||
| Line 216: | Line 476: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== mautrix-whatsapp === | |||
Packaged as [https://search.nixos.org/packages?query=mautrix-whatsapp mautrix-whatsapp]. | Packaged as [https://search.nixos.org/packages?query=mautrix-whatsapp mautrix-whatsapp]. | ||
=== matrix-appservice-irc === | |||
NixOS-specific module options: TODO link to the search results once it's landed | NixOS-specific module options: TODO link to the search results once it's landed | ||
| Line 282: | Line 538: | ||
The appservice automatically creates a registration file under <code>/var/lib/matrix-appservice-irc/registration.yml</code> and keeps it up to date. If your homeserver is not located on the same machine and NixOS installation, you must absolutely make sure to synchronize that file over to the home server after each modification and keep both in sync. | The appservice automatically creates a registration file under <code>/var/lib/matrix-appservice-irc/registration.yml</code> and keeps it up to date. If your homeserver is not located on the same machine and NixOS installation, you must absolutely make sure to synchronize that file over to the home server after each modification and keep both in sync. | ||
=== matrix-appservice-discord === | |||
Full configuration reference: | Full configuration reference: | ||
https://github.com/Half-Shot/matrix-appservice-discord/blob/master/config/config.sample.yaml | https://github.com/Half-Shot/matrix-appservice-discord/blob/master/config/config.sample.yaml | ||