Matrix and messaging bridges
Enable the Matrix server (Synapse), its Element web client and mautrix bridges (WhatsApp, Signal, Telegram, Messenger, Discord). For the architecture, see Matrix in DNF.
Enable Matrix
Section titled “Enable Matrix”-
Declare the services on the target host in
etc/config.yaml:etc/config.yaml services:matrix:title: "Matrix"description: "Messagerie instantanée"element: # client webturn: # audio/video relay (recommended) -
Declare the Matrix administrator (global key, outside hosts) :
etc/config.yaml matrix:admin: "alice" # local part of the admin accountThis account administers the bridges and receives supervision alerts.
-
Create the required secrets (see table below), then deploy.
Authentication goes through SSO Kanidm (OIDC) : every declared user connects with their network account, no Matrix account creation is needed.
Required secrets
Section titled “Required secrets”To fill in usr/secrets/secrets.yaml :
| Sops key | Role | Generation |
|---|---|---|
matrix-rss-password | Synapse registration shared secret | openssl rand -hex 32 |
oidc-secret-matrix | OIDC Kanidm client secret | see SSO |
turn-secret | coturn shared secret (if turn enabled) | openssl rand -hex 32 |
mautrix-doublepuppet-as-token | double puppeting appservice token (shared by bridges) | openssl rand -hex 32 |
mautrix-doublepuppet-hs-token | Same, required by Synapse, never used | openssl rand -hex 32 |
Managing bridges
Section titled “Managing bridges”WhatsApp, Signal, Telegram and Messenger bridges are enabled by default with Matrix ; Discord is disabled by default. Per-host setting in the machine’s nix configuration :
# usr/machines/<host>/default.nixdarkone.service.matrix.bridges = { discord.enable = true; # opt-in messenger.enable = false; # disable a default bridge};Each bridge has its own secrets :
| Bridge | Sops keys | Note |
|---|---|---|
mautrix-whatsapp-as-token, mautrix-whatsapp-hs-token, mautrix-whatsapp-encryption-pickle-key | openssl rand -hex 32 each | |
| Signal | mautrix-signal-as-token, mautrix-signal-hs-token, mautrix-signal-encryption-pickle-key | openssl rand -hex 32 each |
| Messenger | mautrix-meta-as-token, mautrix-meta-hs-token, mautrix-meta-encryption-pickle-key | openssl rand -hex 32 each |
| Telegram | mautrix-telegram-api-id, mautrix-telegram-api-hash, mautrix-telegram-as-token, mautrix-telegram-hs-token | API id/hash to create on my.telegram.org 🡕 |
| Discord | mautrix-discord-as-token, mautrix-discord-hs-token | openssl rand -hex 32 each |
The as/hs tokens make each bridge’s appservice registration
deterministic (see
appservice tokens).
Permissions
Section titled “Permissions”Nothing to manage : any local account (@*:domain.tld) can use each
bridge with their own remote account, without interference between
users. The matrix.admin account has the bot administration
commands (help in direct conversation with the bot for the
list).
Double puppeting
Section titled “Double puppeting”Bridges share a doublepuppet appservice (token
mautrix-doublepuppet-as-token) : messages sent from the
phone appear in Matrix as coming from the user’s real account.
This is automatic for all local accounts, no action per
user.
Operations
Section titled “Operations”| Action | Command |
|---|---|
| Service status | systemctl status matrix-synapse mautrix-whatsapp mautrix-signal mautrix-telegram mautrix-meta-messenger |
| Bridge logs | journalctl -u mautrix-whatsapp -f |
| Synapse logs | journalctl -u matrix-synapse -f |
Diagnosing a mute bot
Section titled “Diagnosing a mute bot”A bot that does not respond to help while its service is running almost
always falls into one of two cases : its tokens no longer match the
registration loaded by Synapse, or it receives messages but cannot
decrypt them. Diagnosis in order :
-
Is the service actually running ?
Fenêtre de terminal systemctl status mautrix-<bridge>journalctl -u mautrix-<bridge> -n 50If it keeps restarting with « The as_token was not accepted », Synapse’s in-memory registration no longer matches the bridge’s tokens (typical after a reset or migration, see the callout above) :
systemctl restart matrix-synapse, then restart the bridge. -
Does the message reach the bridge ? Follow Synapse while sending a
helpto the bot :Fenêtre de terminal journalctl -u matrix-synapse -f | grep transactionsA line
PUT .../_matrix/app/v1/transactions/... 200should appear. If nothing goes out, the appservice is not loaded : check for the registration file in/var/lib/mautrix-<bridge>/and restart Synapse. -
Can the bridge decrypt it ? If the transaction goes through (200) but the bot remains mute, follow its logs during a new message :
Fenêtre de terminal journalctl -u mautrix-<bridge> -fLook for
decrypt,session,verification,dropping. A decryption failure means the room session key was not shared with the bot’s current device (classic case after a bridge reset : its e2ee identity has changed). -
Recreate the conversation. Leave the direct message with the bot and start a new one : the client establishes a fresh encryption session and shares the key with the bot’s current device. Check along the way that your own Element session is verified.
-
Last resort : reset the bridge state (callout below), then restart Synapse to reload the registration.
See also
Section titled “See also”- Matrix messaging: user guide : bridge connection for users
- Matrix in DNF : architecture and implementation