Introduction
This book contains the documentation for all my Matrix bridges. The book is built using mdBook. The source code is available in the mautrix/docs repo.
These docs are mostly targeted towards people who want to run bridges themselves. If you don't want to self-host, some bridges have public instances available (listed on the page of each bridge). Beeper also offers all of these bridges as a paid service.
Troubleshooting & FAQ
Debugging setup issues should be done in the Matrix rooms for the bridges (linked in the READMEs), rather than in GitHub issues. Additionally, this page will collect some of the most common issues.
Why is the bridge bot not accepting invites? (or not receiving messages from Matrix)
If the bridge starts up successfully, but inviting the bot doesn't work and the logs don't show any errors, it usually means the homeserver isn't sending events to the appservice.
In the case of mautrix-imessage, there's no need to invite the bot for setup, so this issue manifests as outgoing messages not working.
There are a few potential reasons this can happen:
- There was a misconfiguration in the appservice address/hostname/port config
or the homeserver can't reach the appservice for some other reason. The
homeserver logs should contain errors in this case (grep for
transactions
in Synapse'shomeserver.log
).- Note that grepping for
transactions
will show some data even when it's working correctly. If it shows nothing at all, something is broken. - Also note that
transaction
is not the same astransactions
. If you don't include thes
at the end, you'll get tons of unrelated logs. - For mautrix-imessage, you should also check the wsproxy logs.
- As of Synapse v1.84 and bridges released after May 2023, the bridges will automatically use the appservice ping mechanism to detect configuration issues and report them in bridge logs.
- Note that grepping for
- The bridge was down for longer than a few minutes and the homeserver backed off. The homeserver should retry after some time. If it still doesn't work after an hour or so (exact backoff depends on how long the bridge was down), check the homeserver logs.
I don't see any responses from the bridge bot in Matrix, but the responses are visible in the bridge logs
Make sure you didn't ignore the bot.
Settings -> Security & Privacy -> Advanced -> Ignored users on Element.
Why are direct messages showing up under "Rooms" instead of "People"?
All chats in Matrix are actually rooms, and there's no good way for bridges to
declare that a room is a DM. Specifically, the DM status is stored in the
user's account data in the m.direct
event, rather than in the room itself.
Since the flag isn't stored in the room, there's no way for the room creator
to force the room to be a DM.
The bridges include a hacky workaround, which uses double puppeting to update
the m.direct
account data event directly. It can be turned on with the
sync_direct_chat_list
config option. Alternatively, you can manually add
individual rooms using the /converttodm
command in Element Web/Desktop.
Canonical DMs (MSC2199) should fix the issue permanently by actually storing the DM status in the room itself, but so far it has not been implemented in any clients or servers.
How do I bridge typing notifications and read receipts?
Bridging ephemeral events (EDUs) is enabled by default in the bridges, but currently those events aren't sent to appservices by default. There are two config options to enable the bridges to receive EDUs:
bridge
->sync_with_custom_puppets
- calls/sync
with your Matrix account to receive EDUs. See the double puppeting docs for how to enable double puppeting in general.appservice
->ephemeral_events
- enables MSC2409 support to have the homeserver push EDUs directly to the bridge (the same way it pushes normal messages).- This is currently only implemented in Synapse.
- This also requires the
de.sorunome.msc2409.push_ephemeral
field in the registration file to be set totrue
. If you regenerate the registration after enabling the config option, the relevant fields will be added automatically. Remember to restart Synapse after updating the registration.
You should only have one of the two enabled at any time.
Why are contact list names disabled by default?
Some bridges like WhatsApp and Signal have access to the contact list you've uploaded to their servers. However, the bridges will not use those names by default. The reason is that they cause problems if your bridge has multiple Matrix users with the same people in their contact lists.
- Contact list names might be leaked to other Matrix users using the same bridge.
- Per-room displaynames could somewhat mitigate this, but even that wouldn't work if you're in some bridged groups with the other Matrix users.
- Bridge ghosts might flip between names from different Matrix users' contact lists.
If the bridge only has one user, then contact list names should be safe to enable.
Signal: Identity failure occurred while sending message to +phone
This error happens if the remote user's encryption identity changed (e.g. if they reinstalled Signal). In groups, it usually means one or more of the participants changed devices, but the message was still sent to everyone else.
To solve it, you can either use !signal safety-number +phone
and then copy
the safety number to the mark-trusted
command, or you can run signald with
the --trust-new-keys
and --trust-all-keys-on-start
CLI options to have it
automatically trust new keys. See https://signald.org/articles/config/ for
more info on those options.
pip
failed building wheel for python-olm
fatal error: olm/olm.h: no such file or directory
When building with end-to-bridge encryption, you must have a C compiler, python3 dev headers and libolm3 with dev headers installed.
If you want to build without encryption:
- For Python bridges, don't install the
e2be
optional dependency. - For Go bridges, either build with
-tags nocrypto
or disable cgo with theCGO_ENABLED=0
env var.
fatal error: olm/pk.h: no such file or directory
libolm2 is too old, you need libolm3.
fatal error: pyconfig.h: no such file or directory
python3-dev is required.
error: command 'gcc' failed: No such file or directory
build-essential is required.
Configuration error: <field>
not configured
You didn't change the value of <field>
in the config, but that field must be
configured for the bridge to work (i.e. the default value will not work). Dots
in <field>
mean nesting, e.g. bridge.permissions
means the permissions
field inside the bridge
object.
ForeignTablesFound: The database contains foreign tables
As mentioned in the setup page, you should not share a single Postgres database between unrelated programs.
You can create a separate database either using the createdb
shell command
that is usually included with Postgres, or the CREATE DATABASE
SQL statement.
For existing installations, you can use the flag suggested in the error message
and hope that there are no table name conflicts in the future. To use the flag
in Docker, you'll have to override the startup command, either with a copy of
the docker-run.sh
script (which can be found in the bridge repo), or just
the startup command (python3 -m mautrix_$bridge -c /data/config.yaml --flags
).
The as_token
was not accepted
This error means you either:
- didn't add the path to the registration file to the homeserver config,
- didn't restart the homeserver after adding the path to the config, or
- modified the tokens somewhere and didn't copy them to the other file
Make sure the tokens match everywhere, that you're looking at the right files, and that everything has been restarted.
The as_token
was accepted, but the /register
request was not
This can happen if you either misconfigure the homeserver
-> domain
field,
or change the username_template
without regenerating the registration.
Usually it's the former, so make sure that the domain
field matches your
homeserver's server_name
exactly. If it doesn't, fix it, regenerate the
registration file and restart everything.
Registering appservices
All the bridges here use the Matrix Application Service API. It's mostly the same as the client-server API, but there are a few key differences. Primarily, it means that the bridges
- can control any user ID in a predefined namespace, e.g. all user IDs starting
with
@telegram_
and ending with:yourserver.com
, - don't have rate limits, and
- have events pushed to them via HTTP, instead of pulling with long polling like normal Matrix clients do.
To get these special privileges, the bridge must be registered on the homeserver as an appservice. In general, this requires root access to the server. Instructions for individual homeserver implementations can be found below.
All of the instructions below require you to have the registration.yaml
file
ready, so make sure you've reached the point in the bridge setup instructions
where it tells you to register the bridge on your homeserver.
The registration file is only necessary for the homeserver. None of the mautrix bridges will try to read it at runtime, as all the relevant information is also in the bridge-specific config file. However, this also means that if you change certain config fields, you must regenerate the registration file (or manually apply the relevant changes). The config fields that affect the registration are:
homeserver
->domain
appservice
->address
appservice
->bot_username
(orbot
->username
in Go bridges)appservice
->ephemeral_events
appservice
->id
appservice
->as_token
appservice
->hs_token
bridge
->username_template
bridge
->alias_template
(Telegram only)
Synapse
If necessary, copy the registration file somewhere where Synapse can read it.
Then add the path to the file under app_service_config_files
in Synapse's
homeserver.yaml
file. The field must be an array of strings, for example:
app_service_config_files:
- /data/mautrix-telegram-registration.yaml
After updating the config, restart Synapse to apply changes. If you change or regenerate the registration file, you will need to restart Synapse every time.
If Synapse fails to start after editing the config, it means you either made a YAML syntax error, or the file path is incorrect or not readable. See the Synapse logs to find out what went wrong exactly.
Some things to keep in mind:
- When using Docker, the file needs to be mounted inside the container
- If Synapse is running through systemd, the service file might have security hardening features that block access to certain paths.
Beeper
Follow the instructions at github.com/beeper/bridge-manager.
Dendrite
Dendrite works the same way as Synapse, except the relevant config field is
config_files
under app_service_api
(and the config file is usually called dendrite.yaml
rather than homeserver.yaml
):
app_service_api:
...
config_files:
- /data/mautrix-telegram-registration.yaml
Conduit
Conduit doesn't use a config file, instead it has an admin command for
registering appservices. Go to the admin room (which is created automatically
when the first user is registered on the server), copy the contents of the
registration YAML file, then send a register_appservice
command:
@conduit:your.server.name: register_appservice
```
paste registration.yaml contents here
```
(replacing your.server.name
with the server name. You can also use tab
autocompletion to mention the @conduit
user in most clients).
You can confirm it worked using the list_appservices
command (which should
show the id
field of the just registered appservice):
@conduit:your.server.name: list_appservices
See also: https://gitlab.com/famedly/conduit/-/blob/next/APPSERVICES.md
Construct
-
Review the following to tweak your registration.yaml:
-
Add the prefix "bridge_" to the
as_token
. Example:as_token: bridge_1m9jt3xt6qdb4...
-
The bridge
id
and thesender_localpart
have to match. Choose a simple name such as the service being bridged.
A bridge user and room will be created automatically based on the
id
(e.g.!id:localhost
). It is also okay if these already exist. -
-
Convert the
registration.yaml
toregistration.json
using a yaml2json converter such asreserialize
or a website.apt-get -y install reserialize reserialize yaml2json registration.yaml > registration.json
-
Use the console to enter the command:
bridge set /path/to/registration.json
If the bridge has already been registered before then the prior configuration will be overwritten.
The registration will take effect immediately without restarting the server or reloading the bridge module.
The console command
bridge
will list all bridges by ID.bridge <id>
will confirm the configuration for the bridge.The following are all functionally equivalent:
- With terminal access strike
ctrl-c
and enterbridge set /path/to/registration.json
at the prompt. - Operator sends message
bridge set /path/to/registration.json
to the!control
room. - Operator sends server-side private-command prefix
\\control bridge set /path/to/registration.json
(any client, any room). - Non-interactive registration add the argument
-execute "bridge set /path/to/registration.json"
when running the server. - Non-interactive registration for multiple bridges: use multiple
-execute
arguments:-execute "bridge set registration1.json" -execute "bridge set registration2.json"
- With terminal access strike
See also: https://github.com/matrix-construct/construct/wiki/Bridges
End-to-bridge encryption
The bridge can optionally encrypt messages between Matrix users and the bridge to hide messages from the homeserver. Using Postgres is strongly recommended when using end-to-bridge encryption.
To enable it, you must install the bridge with dependencies:
- For Python-based bridges, install the
e2be
optional dependency. - For Go-based bridges, make sure the bridge is built with libolm.
- CI binaries from mau.dev and release binaries on GitHub are always built with libolm.
After that, simply enable the option in the config (bridge
→ encryption
).
If you only set allow: true
, the bridge won't enable encryption on its own,
but will work in encrypted rooms. If you also set default: true
, the bridge
will automatically enable encryption in new portals.
You should not set appservice: true
at the moment, as the Synapse
implementation is still incomplete and has not been tested with the bridges.
Note that end-to-bridge encryption does not currently work on Dendrite as it doesn't implement the necessary parts of the spec. The critical missing piece is tracked in matrix-org/dendrite#2723. Additionally, Conduit only supports it starting from v0.6.0.
Legacy registration file workaround
In mautrix-telegram v0.8.0 release candidates, you had to manually apply a workaround for MSC2190. In newer versions (mautrix-telegram v0.8.0+, mautrix-python v0.5.0-rc3+) the workaround is applied automatically to all newly generated registration files. For old registration files, you can either regenerate the file or apply the workaround manually:
- Change
sender_localpart
in the registration to something else. Any random string will do. - Add a new entry in the
users
array for the bridge bot (the previous value ofsender_localpart
). If you used the defaulttelegrambot
, the result should look something like this:namespaces: users: - exclusive: true regex: '@telegram_.+:your.homeserver' - exclusive: true regex: '@telegrambot:your.homeserver'
Using theThis step only applies to new bridges, but new bridges don't need to do this workaround.as_token
, make a call to register the bot user. It's fine if this says the user is already in use.$ curl -H "Authorization: Bearer <as_token>" -d '{"username": "telegrambot"}' -X POST https://your.homeserver/_matrix/client/r0/register?kind=user
Double puppeting
You can replace the Matrix ghost of your remote account with your Matrix account. When you do so, messages that you send from other clients will be sent from your Matrix account instead of the default ghost user. In most of the bridges, this is necessary to bridge DMs you send from other clients to Matrix.
Also, in servers that don't support MSC2409 (i.e. Synapse before v1.22), it is
the only way to enable bridging of ephemeral events, such as presence, typing
notifications and read receipts. If you want to use MSC2409 for ephemeral
events, make sure appservice
-> ephemeral_events
is set to true
in the
bridge config and that the registration file has the appropriate flags too
(you can regenerate the registration after updating the bridge config).
Manually
Double puppeting can only be enabled after logging into the bridge. As with the normal login, you must do this in a private chat with the bridge bot.
N.B. This method is not currently supported in mautrix-imessage and mautrix-slack.
- Log in on the homeserver to get an access token, for example with the command
You may want to change the$ curl -XPOST -d '{"type":"m.login.password","identifier":{"type": "m.id.user", "user": "example"},"password":"wordpass","initial_device_display_name":"a fancy bridge"}' https://example.com/_matrix/client/v3/login
initial_device_display_name
field to something more descriptive, or rename it from another client after logging in.- In the past, getting a token from an existing client like Element was the recommended easy way. However, multiple clients using the same token can cause issues with encryption, so doing that is no longer allowed.
- Send
login-matrix <access token>
to the bridge bot. For the Telegram bridge, sendlogin-matrix
without the access token, then send the access token in a separate message. - After logging in, the default Matrix ghost of your remote account should leave rooms and your account should join all rooms the ghost was in automatically.
Automatically
Instead of requiring everyone to manually enable double puppeting, you can give the bridge access to log in on its own. This makes the process much smoother for users, and removes problems if the access token getting invalidated, as the bridge can simply automatically relogin.
This method requires administrator access to the homeserver, so it can't be used if your account is on someone elses server (e.g. using self-hosted bridges from matrix.org). In such cases, manual login is the only option.
Shared secret method
- Set up matrix-synapse-shared-secret-auth on your Synapse.
- Make sure you set
m_login_password_support_enabled
totrue
in the config. - You should also set
com_devture_shared_secret_auth_support_enabled
tofalse
as having that option enabled breaks user-interactive auth in some clients (e.g. you won't be able to sign out other devices or reset cross-signing in Element).
- Make sure you set
- Add the login shared secret to
bridge
→login_shared_secret_map
in the config file under the correct server name.- In mautrix-imessage and in past versions of other bridges, the field is
called
login_shared_secret
, as double puppeting was only supported for local users.
- In mautrix-imessage and in past versions of other bridges, the field is
called
- The bridge will now automatically enable double puppeting for all users on servers with a shared secret set when they log into the bridge.
Appservice method
This method is experimental and may have unexpected side-effects.
Potential side-effects include:
- Push notifications not working due to bugs in Synapse (#2211)
- The bridge bot joining rooms unexpectedly when events are pushed to it
- Other unknown effects
Additionally, it only works for users who are on the same homeserver as the bridge, it can't be used with other homeservers at all (even with admin access).
The benefit of this method is that appservice login is in the spec, so it can work on all homeserver implementations (caveat: as of writing, Dendrite and Conduit do not implement the spec).
-
Modify the registration file to add a user namespace covering all users in addition to the
bridge_.+
andbridgebot
regexes. Make sure you setexclusive: false
for the new regex.namespaces: users: - ...existing regexes... - regex: '@.*:your\.domain' exclusive: false
Restart the homeserver after modifying the registration.
-
Set the shared secret in the bridge config to
appservice
:bridge: ... login_shared_secret_map: your.domain: appservice ...
-
The bridge will now use appservice login enable double puppeting for all local users when they log into the bridge.
Relay mode
Some of the bridges here support relaying messages for unauthenticated users through the account that another Matrix user is logged in as.
- Enable relay mode by setting
bridge
→relay
→enabled
totrue
in the bridge config. Also make sure that the users you want to invite have at least therelay
level in thepermissions
section. - Log into the bridge normally using the relaybot account.
- If you want a separate remote account for the relaybot while using your own account for your own Matrix user, you should make a dedicated Matrix account for the relaybot. If you do this, make sure to run the next command using the new Matrix account too.
- Using the same dedicated account for multiple bridges is fine, so you can have a server-wide "relay" account that acts as the relay for all the bridges.
- Run
!prefix set-relay
in the chats where you want to use the relaybot. (replace!prefix
with the appropriate command prefix for the bridge, like!signal
or!wa
) - Use
!prefix set-pl 100
to be able to modify room settings and invite others.
If you want to bridge existing rooms, you'll have to manually update the mxid
column in the portal
table to point to the room you want bridged.
Note that reactions from relayed users will not be bridged at all, because the bot wouldn't be able to bridge sender info nor multiple reactions of the same emoji.
Support table
Minimum bridge versions that support the relay system documented above.
Bridge | Version |
---|---|
Telegram | Different system |
0.2.0 | |
Signal | 0.2.0 |
0.1.2 | |
0.3.3 | |
Google Chat | not yet supported |
not yet supported | |
iMessage | †0.1.0/3df789e2 |
Discord | Different system |
Slack | not yet supported (will likely use different system) |
† iMessage doesn't require set-relay
, relay mode is enabled in all chats
automatically if enabled in the config. The permissions
section is replaced
with relay
-> whitelist
.
Bridge setup with Docker
Please select a bridge above. If you don't select a bridge, you'll have to
manually replace occurrences of $bridge
with the correct name before running
commands.
This page contains instructions for setting up the bridge in Docker. To set up the bridge outside of Docker, see the language-specific instructions: Python, Go (to find out which bridge language the bridge you want is written in, check the sidebar to see which section it's under).
If you need help with setting up the bridge, you can ask in the Matrix room: #$bridge:maunium.net. For help with setting up other parts like the homeserver that aren't the bridge, refer to their documentation to find support rooms.
Requirements
- Docker
- A Matrix homeserver that supports application services (e.g. Synapse) You need access to register an appservice, which usually involves editing the homeserver config file.
- mautrix-whatsapp: A WhatsApp client running on a phone or in an emulated Android VM.
Setup
Docker images are hosted on dock.mau.dev. Available docker tags are generally
:latest
, :git tag
, :git commit-amd64
and :git commit-arm64
. The latest
and git tag specific docker tags are manifests that contain both amd64 and
arm64 images.
- Create a directory for the bridge and cd into it:
mkdir mautrix-$bridge && cd mautrix-$bridge
.
N.B. The docker image willchown
its/data
directory to UID 1337. The commands below mount the working directory as/data
, so make sure you always run them in the correct directory. - Pull the docker image with
docker pull dock.mau.dev/mautrix/$bridge:<version>
. Replace<version>
with the version you want to run (e.g.latest
orv0.6.0
). - Run the container for the first time, so it can create a config file for you:
docker run --rm -v `pwd`:/data:z dock.mau.dev/mautrix/$bridge:<version>
- Update the config to your liking. You'll at least need to change the
homeserver settings, appservice address, database address and bridge
permissions. If you miss something that's required, the bridge will refuse
to start and tell you what's missing.
- Keep in mind that
localhost
is not the correct address inside Docker (unless usingnetwork=host
mode). Usually you should have the bridge and homeserver in the same Docker network, and use the container names as addresses (e.g.http://mautrix-$bridge:$bridgeport
andhttp://synapse:8008
). - Make sure you don't share databases between unrelated programs. Shared postgres instance is fine, but shared database is not.
- Keep in mind that
- Generate the appservice registration by running the container again, same command as above.
- Register the bridge on your homeserver (see Registering appservices).
- Run the bridge:
Additionally, you should either add the bridge to the same Docker network as Synapse withdocker run --restart unless-stopped -v `pwd`:/data:z dock.mau.dev/mautrix/$bridge:<version>
--network=synapsenet
(when both are running in Docker), or expose the correct port with-p $bridgeport:$bridgeport
(when the homeserver is outside Docker).
Upgrading
- Pull the new version (setup step 1)
- Start the new version (setup step 6)
Docker compose
- Create a directory for the bridge like step #0 in the Docker CLI instructions above.
- Create
docker-compose.yml
that contains something like this:version: "3.7" services: mautrix-$bridge: container_name: mautrix-$bridge image: dock.mau.dev/mautrix/$bridge:<version> restart: unless-stopped volumes: - .:/data # If you put the service above in the same docker-compose as the homeserver, # ignore the parts below. Otherwise, see below for configuring networking. # If synapse is running outside of docker, you'll need to expose the port. # Note that in most cases you should either run everything inside docker # or everything outside docker, rather than mixing docker things with # non-docker things. #ports: #- "$bridgeport:$bridgeport" # You'll also probably want this so the bridge can reach Synapse directly # using something like `http://host.docker.internal:8008` as the address: #extra_hosts: #- "host.docker.internal:host-gateway" # If synapse is in a different network, then add this container to that network. #networks: #- synapsenet # This is also a part of the networks thing above #networks: # synapsenet: # external: # name: synapsenet
- Follow the rest of the Docker setup, but use compose commands instead of the
raw
docker
commands:docker-compose up -d
to start,docker-compose stop
to stop anddocker-compose pull
to update.
If you want to set it up in an existing docker-compose file instead of a new
dedicated one, simply adjust the volumes
section to mount a subdirectory
instead of the current directory as the data directory:
volumes:
- ./mautrix-$bridge:/data
When you put the bridge and Synapse in the same docker-compose file, networking
should work out of the box, which means you don't need any of the commented
ports
or networks
things in the example compose file.
Python bridge setup
Please select a bridge above. If you don't select a bridge, you'll have to
manually replace occurrences of $bridge
with the correct name before running
commands.
This page contains instructions for setting up the bridge in a virtualenv. You may also want to look at other ways to run the bridge:
- Docker
- YunoHost: mautrix_telegram_ynh, mautrix_signal_ynh, mautrix_facebook_ynh
- systemd service (at the bottom of this page)
Please note that everything in these docs are meant for server admins who want to self-host the bridge. If you're just looking to use the bridges, check out Beeper, which provides fully managed instances of all of these bridges.
If you need help with setting up the bridge, you can ask in the Matrix room: #$bridge:maunium.net. For help with setting up other parts like the homeserver that aren't the bridge, refer to their documentation to find support rooms.
Requirements
- Python 3.9 or higher with
pip
andvirtualenv
.- 3.10 or higher is recommended, 3.9 support will be dropped some time after Debian 12 is released.
- A Matrix homeserver that supports application services (e.g. Synapse). You need access to register an appservice, which usually involves editing the homeserver config file.
- A PostgreSQL server, v10 or higher (which you should already have for Synapse).
- Make sure you don't share databases between unrelated programs. Shared postgres instance is fine, but shared database is not.
- If installing optional dependencies, see the optional dependencies page.
- mautrix-telegram: Telegram app ID and hash (get from my.telegram.org).
- mautrix-telegram: LottieConverter if you want animated stickers to be converted to something viewable on Matrix.
- Bridges with voice messages: ffmpeg to transcode audio files (just install it with your system package manager).
- mautrix-signal: An instance of signald.
Production setup
Don't use sudo
for any of these steps (and preferably don't use the root user either).
- Create a directory for the bridge. Do not clone the repository.
- Set up a virtual environment.
- Create with
virtualenv -p /usr/bin/python3 .
(note the dot at the end)- You should not use a subdirectory for the virtualenv in this production
setup. The
pip install
step places some required files at the root of the environment.
- You should not use a subdirectory for the virtualenv in this production
setup. The
- Activate with
source ./bin/activate
- Create with
- Install the bridge with
pip install --upgrade mautrix-$bridge[all]
[all]
at the end will install all optional dependencies. This includes end-to-bridge encryption, which requires libolm3. See the optional dependencies page for more info.- If you want the master branch instead of a release, use
pip install --upgrade git+https://github.com/mautrix/$bridge.git#egg=mautrix-$bridge[all]
.
- Copy
example-config.yaml
toconfig.yaml
. - Update the config to your liking. You'll at least need to change the homeserver settings, database address, and bridge permissions. If you miss something that's required, the bridge will refuse to start and tell you what's missing.
- Generate the appservice registration with
python -m mautrix_$bridge -g
. You can use the-c
and-r
flags to change the location of the config and registration files. They default toconfig.yaml
andregistration.yaml
respectively. - Register the bridge on your homeserver (see Registering appservices).
- Run the bridge
python -m mautrix_$bridge
.
Upgrading (production setup)
- Make sure you're in the virtualenv (
source ./bin/activate
). - Run the bridge install command again (install step #2).
Development setup
- Clone the repository.
- Optional, but strongly recommended: Set up a virtual environment.
- Create with
virtualenv -p /usr/bin/python3 .venv
- Activate with
source .venv/bin/activate
- Create with
- Install dependencies with
pip install --upgrade -r requirements.txt
- Optionally, add
-r optional-requirements.txt
to install optional dependencies. Some of the optional dependencies may need additional native packages. See the optional dependencies page for more info.
- Optionally, add
- Continue from step #3 of production setup.
- For linting:
pip install -r dev-requirements.txt
to install Black, isort and pre-commit, then install the Git hook withpre-commit install
. This will ensure that code is properly formatted when you commit, to avoid having to fix linting errors when the CI complains.
Upgrading (development setup)
- Make sure you're in the virtualenv (
source .venv/bin/activate
). - Pull changes from Git.
- Run the dependency install command again (install step #2).
systemd service
- Create a user for the bridge:
$ sudo adduser --system mautrix-$bridge --home /opt/mautrix-$bridge
- Follow the production setup instructions above. Make sure you use that user and home directory for the bridge.
- Create a systemd service file at
/etc/systemd/system/mautrix-$bridge.service
:[Unit] Description=mautrix-$bridge bridge [Service] # N.B. If you didn't create a user with the correct home directory, set this # to the directory where config.yaml is (e.g. /opt/mautrix-$bridge). WorkingDirectory=~ ExecStart=/opt/mautrix-$bridge/bin/python -m mautrix_$bridge User=mautrix-$bridge [Install] WantedBy=multi-user.target
Optional dependencies
Usage
Production setup
The pip install URLs in the production setup guide include [all]
at the end
by default, which means all optional dependencies will be installed by default.
If you only want specific optional dependencies, replace the all
with a
comma-separated list of the pip extra names (e.g. sqlite,speedups
).
If you don't want any optional dependencies, just remove the [all]
.
Development setup
To install all optional dependencies, use pip install --upgrade -r optional-requirements.txt
.
To install specific optional dependencies, install the packages listed
"Required packages" from the table of optional dependencies below. You can also
check the expected versions of the packages from optional-requirements.txt
.
Docker
The docker images contain all optional dependencies. Currently they can't be easily disabled.
List of optional dependencies
The †
symbol means you must also enable the feature in the config. Required
packages in parentheses indicate a large dependency of the other packages.
All Python bridges
pip extra name | Required packages | Description |
---|---|---|
†metrics | prometheus_client | Prometheus metrics. |
†e2be | python-olm pycryptodome unpaddedbase64 | End-to-bridge encryption support (see native dependency below). |
†sqlite | aiosqlite | Experimental SQLite support (currently in Telegram/Facebook/Signal) |
N.B. python-olm requires libolm3 with dev headers, Python dev headers, and
a C compiler. This means libolm-dev
, python3-dev
and build-essential
on
Debian 11+ and Ubuntu 19.10+. On older Debian-based distros, install
libolm-dev
from backports.
If you want to avoid the dev headers, you can install the libolm3 package without -dev and get a pre-compiled python-olm from gitlab.matrix.org's PyPI registry. However, this method has not been tested properly, so it might not work at all.
pip install python-olm --extra-index-url https://gitlab.matrix.org/api/v4/projects/27/packages/pypi/simple
mautrix-telegram
pip extra name | Required packages | Description |
---|---|---|
speedups | cryptg cchardet aiodns brotli | Speed up some things, e.g. by using native crypto code. |
qr_login | qrcode Pillow | Telegram login by scanning a QR code from another device. |
formattednumbers | phonenumbers | Format phone numbers nicely in contact share messages |
mautrix-facebook
pip extra name | Required packages | Description |
---|---|---|
animated_stickers | Pillow | Finds the dimensions of stickers bridged from Facebook. |
†proxy | pysocks aiohttp-socks | Support for proxying all Facebook traffic through a SOCKS5 proxy. |
mautrix-instagram
pip extra name | Required packages | Description |
---|---|---|
imageconvert | Pillow | Convert images from Matrix into JPEG so Instagram would accept them. |
mautrix-signal
pip extra name | Required packages | Description |
---|---|---|
formattednumbers | phonenumbers | Format phone numbers nicely before using as displaynames. |
qrlink | qrcode Pillow | Generate QR codes required for linking as a secondary device. |
stickers | signalstickers-client | Enable bridging of Signal stickers to Matrix. |
Manhole
The "manhole" allows server administrators to access a Python shell on a running bridge. This is a very powerful mechanism for administration and debugging.
To enable it, update the config and restart the bridge: set manhole
->
enabled
to true
and manhole
-> whitelist
to the list of system UIDs you
want to allow connecting. After that, send open-manhole <uid>
to the bridge
bot on Matrix as a bridge admin user to open the manhole for the given UID.
When the manhole is open, you can open a connection with nc -NU /var/tmp/mautrix-telegram.manhole
in your normal shell. Optionally, install
rlwrap
and use rlwrap nc
instead of nc
to get a nicer prompt. To use
rlwrap
with Docker, run it on the host: rlwrap docker exec -i nc -NU /var/tmp/mautrix-telegram.manhole
. Alternatively, you can mount the socket to
the host and connect with the hosts netcat and rlwrap.
To close the connection, use Ctrl+C or exit()
. To close
the manhole, use the close-manhole
management command or use manhole.close()
inside the manhole.
Inside the manhole, bridge
refers to the main class instance. Refer to the
source code to see how everything works. The manhole supports top-level await
expressions similar to python -m asyncio
.
mautrix-telegram
Welcome to the mautrix-telegram docs!
Use the sidebar to find the relevant pages. Things that are the same for all bridges, like setting up the bridge, are right below the "Python-based bridges" header. Things specific to mautrix-telegram are under this page.
These docs are mostly targeted towards people who are hosting the bridge themselves. If you don't want to host it yourself, you can use a public instance. When using public instances, refer to their instructions and support rooms.
- beeper.com (paid service with lots of bridges)
- t2bot.io / #help:t2bot.io (only relay bridging, puppeting is disabled)
- tchncs.de / #tchncs:tchncs.de
- snt.utwente.nl / #telegram:utwente.io
- one.ems.host / #one:element.io (paid service with a few bridges, no end-to-bridge encryption)
If you run a public instance and wish to list it here, please make a pull request.
Discussion
Matrix room: #telegram:maunium.net
Telegram chat: t.me/mautrix_telegram (bridged to Matrix room)
Authentication
Logging in
As logging in requires you to send the phone code and possibly also your 2FA password, make sure to run the commands in a management room (i.e. a room with no other users than you and the appservice bot).
If you have 2-factor auth enabled or if you are logging in with a bot token, you should use the web login, as otherwise the homeserver database will likely contain your password/token in plaintext form.
- Start a chat with the bridge bot (
@telegrambot:example.com
by default)- If the bot doesn't accept the invite, see the troubleshooting page
- Initiate the login process with
login
. - The bot should tell you to use the web interface or login in-Matrix. If you have enabled both login modes in the config, the bot will give you both options.
- Choose the login method you want and follow the instructions under that heading, then go to the "Finally" section.
In-Matrix login
- Send your phone number to the room.
- The bot should prompt you to send your auth code to the room: send it once it does.
- If you have two-factor authentication enabled, again wait for the prompt and then send your password to the room.
Web login
New in version 0.2.0
- Click the link sent by the bot, enter your phone number and click "Request code".
- Enter your code and click "Sign in".
- If you have two-factor authentication enabled, enter your password and click "Sign in" again.
Bot token
New in version 0.3.0
You can also log in with your own relay bot. This is more limited than real accounts, but it means you can appear as yourself on Telegram without giving the bridge access to your real account.
In-Matrix
- Send your bot token to the room.
Web
- Click the link sent by the bot and click "Use bot token".
- Enter your bot token and click "Sign in".
Finally: If all went well, the bot should inform you of a successful login, and the bridge should start creating portal rooms for all your Telegram groups and invite you to them. The bridge won't automatically create rooms for private chats: see "Private messages" at the bottom of Creating and managing chats
Registering
Telegram officially discontinued registration from 3rd party clients as of 2023-02-18, so support for it was removed in v0.13.0 of the bridge. You should sign up using a mobile client and then log into the bridge.
You can safely uninstall the mobile client after the bridge is logged in. Telegram is not encrypted, so they don't have a concept of a primary device like WhatsApp and Signal do.
Logging out
Simply run the logout
management command.
Creating and managing chats
Group chats and channels
New Matrix rooms for existing Telegram chats
New portal rooms for existing Telegram chats should be created when:
- The bridge is (re)started
- The user logs in to Telegram
- A message or an invite is received in the Telegram chat
If a portal room is somehow broken, you can tell the bridge to forget it using
the command delete-portal
. The portal room will be recreated when one of the
conditions above is fulfilled. Note that automatic portal creation at
startup/login is only for group chats. Private chat portals are only created
when you receive a message or start a chat.
New Telegram chats for existing Matrix rooms
You can use the create
command to create a new Telegram chat for an existing
Matrix room.
Before running the command, make sure you have invited your appservice bot to
the room, given the bot PL 100 and removed PL 100 from everyone else.
As of 0.2.0, the bridge will function even without power levels.
Existing Telegram chats to existing Matrix rooms
New in version 0.2.0
Get the ID of the Telegram chat with the /id
command of the relay bot. If you
don't have/want a relay bot, figure out another way to get the telegram chat ID,
and make sure it's prefixed (-100
for channels and -
for chats). Then, run
bridge <chat ID>
in the room you want to bridge. Again, make sure that the
appservice bot is in the room and the power levels are correct like in the
previous section.
Matrix ⟷ Telegram mappings
Most Matrix actions are mapped to their Telegram counterparts. Joining, leaving, inviting and kicking are mapped as-is.
Basic power level bridging is implemented. However, there may be some issues that require restarting the bridge to properly sync the power levels. Also, the power level requirements are currently hardcoded as follows:
- Normal groups
- PL 0 = normal user
- PL 50 = admin
- PL 95 = creator
- Supergroups and channels
- PL 0 = normal user
- PL 50 = moderator (i.e. admin who can't add other admins)
- PL 75 = admin
- PL 95 = creator
Private messages
Creating portals
There are three ways to create private chat portals:
- Start a normal Matrix DM (create a room and invite the Matrix ghost of the Telegram user), e.g. by finding a user in the user list of an already bridged group chat. The ghost should join and send confirmation of the portal creation.
- Use the
pm
command. - Send or receive a message on another Telegram client.
Matrix ⟷ Telegram mappings
Most non-messaging Matrix actions are ignored in private chat portals. However, Leaving the portal will cause the portal room to be cleaned up and forgotten.
Bot commands
Initiating chats with bots is no different from initiating chats with real Telegram users.
New in version 0.2.0: The bridge will translate Matrix->Telegram bot commands
at the start of the message from !command
to /command
.
Please note that when messaging a bot for the first time, it may expect you to
run /start
first. The bridge does not do this automatically.
Management commands
These commands can be used to interact with the bridge and Telegram in ways not supported by native Matrix actions.
Management commands only work if the bridge bot is in the room. This means that private chat portals do not currently support management commands.
If the room you send the command to does not have users other than you and the
bridge bot, you do not have to prefix commands, i.e. you can literally write
help
to get the help message. If the room has more users, you must use the
command prefix (!tg
by default). For example: !tg help
. The command prefix
is always allowed even if it's not required.
Generic bridge commands
Command | Usage |
---|---|
help | Show this help message. |
cancel | Cancel an ongoing action (such as login). |
version | View the bridge name and version. |
Authentication
Commands to authenticate with Telegram.
Command | Usage |
---|---|
login [mxid] | Get instructions on how to log in. Admins can use the mxid parameter to log in as another user. |
logout | Log out from Telegram. |
login-matrix | Replace your Telegram account's Matrix ghost with your own Matrix account. |
ping-matrix | Pings the server with the stored matrix authentication. |
ping | Check if you're logged into Telegram. |
ping-bot | Get info of the message relay Telegram bot. |
username <new username> | Change your Telegram username. |
session <list |terminate > [hash] | View or delete other Telegram sessions. |
Creating portals
Commands to make connections to Telegram chats.
Command | Usage |
---|---|
bridge [id] | Bridge the current Matrix room to the Telegram chat with the given ID. The ID must be the prefixed version that you get with the /id command of the Telegram-side bot. |
create [type] | Create a Telegram chat of the given type for the current Matrix. type is either group , supergroup or channel . Defaults to group |
pm <username> | Open a private chat with the given Telegram user. You can also use a phone number instead of username, but you must have the number in your Telegram contacts for that to work. |
join <link> | Join a chat with an invite link. link is a complete t.me invite link, e.g. https://t.me/telegram |
Portal management
Commands to manage the Telegram chats linked to portals. These can only be used in portal rooms and will directly affect the Telegram chat linked to the portal.
Most of these commands require some admin privileges in the Telegram chat: The bot will inform you if you do not have sufficient permissions.
Command | Usage |
---|---|
invite-link | Get a Telegram invite link to the current chat. |
upgrade | Upgrade a normal Telegram group to a supergroup. |
group-name <name|- > | Change the username of a supergroup/channel. To disable, use a dash (- ) as the name. |
delete-portal | Remove all users from the current portal room and forget the portal. Only works for group chats; to delete a private chat portal, simply leave the room. |
unbridge | Remove ghosts from the current portal room and forget the portal. |
Portal configuration
Some bridge settings can be set on a per-portal basis. The !tg config
command is used for that.
Command | Usage |
---|---|
help | View this help text. |
view | View the current config data. |
defaults | View the default config values. |
set <key> <value> | Set a config value. |
unset <key> | Remove a config value. |
add <key> <value> | Add a value to an array. |
del <key> <value> | Remove a value from an array. |
Miscellaneous things
Command | Usage |
---|---|
search [-r|--remote] <query> | Search your contacts or the Telegram servers for users. |
sync [chats |contacts |me ] | Synchronize your chat portals, contacts and/or own info. |
sync-state | Fetch Matrix room state to ensure the bridge has up-to-date info. |
id | Get the ID of the Telegram chat where this room is bridged. |
play <play ID> | Play a Telegram game. |
caption <caption> | Set a caption for the next image or file you send. |
Administration
Bridge admin commands that do advanced things.
Command | Usage |
---|---|
filter-mode <whitelist |blacklist > | Change whether the bridge will allow or disallow bridging rooms by default. |
filter <whitelist |blacklist > <chat ID> | Allow or disallow bridging a specific chat. |
clean-rooms | Clean up unused portal/management rooms. |
set-pl <level> [mxid] | Set a temporary power level without affecting Telegram. |
clear-db-cache <portal |puppet |user > | Clear internal database caches |
reload-user [mxid] | Reload and reconnect a user |
Relay bot
New in version 0.2.0
The bridge supports using a Telegram bot to relay messages for unauthenticated users, allowing Matrix users who are not logged into their Telegram account to chat with Telegram users.
Setup
- If you haven't yet, create a new bot on Telegram by chatting with
@BotFather.
- Make sure you disable privacy mode using BotFather's
/setprivacy
command in order to allow the bot to read messages in groups. - If you added the bot to a group before disabling privacy mode, you'll have to remove the bot and re-add it to apply the change.
- Make sure you disable privacy mode using BotFather's
- Configure the bridge to use the bot you created by setting the token you got
from BotFather in the
telegram
→bot_token
field in the bridge's config. - Restart the bridge and check status with the
!tg ping-bot
command on Matrix. - Invite the relaybot to groups where you want it to bridge messages from
unauthenticated Matrix users. If you're logged in to the bridge, you can use
!tg ping-bot
, click the user pill and click invite directly. If not, you can add the bot on the Telegram side.
If the room was created by the bridge and you don't have invite permissions,
you can either use !tg set-pl
to give yourself permissions, or
/invite <mxid>
(on Telegram) to invite users through the bridge bot.
Creating relaybot portals from Telegram
You can also create portals from Telegram if you have the relay bot set up and
have allowed creating portals from telegram in the config (bridge
→ relaybot
→ authless_portals
). Simply invite the relay bot to your Telegram chat and use
the /portal
command. If the chat is public, the bot should create the portal
and reply with a room alias. If the chat is private, you'll need to invite
Matrix users manually with /invite <mxid>
.
Message format configuration
The format of messages and membership events that the bot sends to Telegram can
be configured both bridge-wide
and per-room. Per-room configs can be managed using the !tg config
command.
For example, to disable bridging of membership events in a room, you can run
!tg config set state_event_formats join: ''
leave: ''
name_change: ''
which sets the state_event_formats
config option to an object containing the
empty strings join
, leave
and name_change
.
Commands
Command | Usage |
---|---|
/invite [mxid] | Invite a Matrix user to the portal room. |
/portal | Create the portal if it does not exist and get the join info. |
/id | Get the prefixed ID of the chat that can be used with !tg bridge and !tg filter in Matrix |
/mxban | Ban a relayed Matrix user. Must reply to a relaybot message. |
/mxkick | Same as mxban, but for kicking |
If you have your own Telegram bot for the bridge, you can copy this to the
/setcommands
BotFather command:
invite - Invite a Matrix user to the portal room.
portal - Create the portal if it does not exist and get the join info.
id - Get the prefixed ID of the chat that can be used with `!tg bridge` and `!tg filter` in Matrix
mxban - Ban a relayed Matrix user. Must reply to a relaybot message.
mxkick - Kick a relayed Matrix user. Must reply to a relaybot message.
Provisioning API
New in version 0.3.0
The provisioning API can be used to sign in and out, and to create and remove bridges. It is primarily intended for integration managers, such as Dimension.
You can find the API spec at https://spec.mau.fi/mxtg-provisioning/
Migrating from Telematrix
New in version 0.3.0
Removed in version 0.11.0
When migrating from Telematrix, you'll need to configure mautrix-telegram to use the same user ID format and bridge bot username. Other options, such as the AS token, port, etc.. don't need to be the same.
The database migration script is located in mautrix_telegram/scripts/telematrix_import. It can be ran using
$ python -m mautrix_telegram.scripts.telematrix_import [arguments...]
The script has three arguments:
-b
/--bot-id
(required) - The internal numeric user ID of the relay bot. This can be fetched fromhttps://api.telegram.org/bot<BOT TOKEN>/getMe
-c
/--config
- The path to the mautrix-telegram config. Used for the database path and might be used for other values in the future (e.g. auto-fetching the bot id). Defaults toconfig.yaml
.-t
/--telematrix-database
- The URL of the telematrix database. Defaults to sqlitedatabase.db
DBMS migration
New in version 0.3.0
Removed in version 0.11.0 (may come back in a future version)
The bridge includes a simple script for migrating between database management systems. It simply reads the data from one database and inserts it into another database.
The script is located in mautrix_telegram/scripts/dbms_migrate. It can be ran using
$ python3 -m mautrix_telegram.scripts.dbms_migrate -f <source db> -t <target db>
Both <source db>
and <target db>
are full database URLs,
e.g. sqlite:///mautrix-telegram.db
and postgres://user:password@localhost/mautrixtelegram
Steps:
- Stop the bridge
- Update the database URI in the config
- Initialize the new database with
alembic upgrade head
- Inside Docker, you need to be in
/opt/mautrix-telegram/
and you need to pass the path to the config withalembic -x config=/data/config.yaml upgrade head
- Inside Docker, you need to be in
- Run the database migration script
- Start the bridge again
mautrix-facebook
Welcome to the mautrix-facebook docs!
Use the sidebar to find the relevant pages. Things that are the same for all bridges, like setting up the bridge, are right below the "Python-based bridges" header. Things specific to mautrix-facebook are under this page.
These docs are mostly targeted towards people who are hosting the bridge themselves. If you don't want to host it yourself, you can use a public instance. When using public instances, refer to their instructions and support rooms.
- beeper.com (paid service with lots of bridges)
If you run a public instance and wish to list it here, please make a pull request.
Discussion
Matrix room: #facebook:maunium.net
Authentication
- Open a private chat with the bridge bot. Usually
@facebookbot:your.server
- If the bot doesn't accept the invite, see the troubleshooting page
Web-based login
New in version 0.2.1
The bridge includes a web-based login interface to prevent the bridge and
homeserver from seeing your Facebook password. The web interface must be
enabled in the config to use this method (appservice
->public
).
After web login is enabled, send login
with no parameters to the bridge bot,
click the link it gives, and use the login form on the website to log in.
In-Matrix login
- Send
login <email>
to the bridge bot.- N.B. Prior to v0.2.1, the syntax is
login <email> <password>
, rather than sending the password in a separate message.
- N.B. Prior to v0.2.1, the syntax is
- Send your password to the room.
- If you have 2FA enabled, the bot will ask you to send the 2FA token.
- Recent chats should now get portals automatically. Other chats will get portals as you receive messages.
Note that in some cases, Facebook might decide your account has suspicious
activity and block you until you do some tasks like adding a phone number or
resetting your password. In most cases, enabling two-factor authentication
solves this. If that doesn't help, hosting the bridge at home or making it proxy
all traffic through a residential IP can help further reduce suspiciousness.
The bridge can run separately from Synapse, e.g. on a Raspberry Pi. It can also
use the http_proxy
environment variable for all Facebook traffic.
Upgrading to v0.2.0
Version 0.2.0 of the bridge includes some major breaking changes:
- It uses a completely different Messenger API, which means that all users will
have to log in again to keep using the bridge. Logging in happens using email
and password instead of stealing cookies like before.
- v0.2.1 includes a web-based login interface that encrypts your password in-browser to prevent the bridge from seeing it.
- There are database schema changes that can not be reversed. Taking a backup before upgrading is recommended. Additionally, only PostgreSQL is supported, see below for SQLite migration instructions.
SQLite migration
If you're using SQLite and want to keep your existing portal rooms, you must
migrate the database to Postgres first. If you don't care about keeping existing
portal rooms, you can use clean-rooms
for cleaning up old portals and enable
backfilling in the config to get message history in the new portals.
The bridge includes a simple script similar to mautrix-telegram's DBMS migration:
$ python -m mautrix_facebook.db.legacy_migrate -f <source db> -t <target db>
Both <source db>
and <target db>
are full database URLs,
e.g. sqlite:///mautrix-facebook.db
and postgres://user:password@localhost/mautrixfacebook
Steps:
- Stop the bridge and update to v0.2.0
- Update the database URI in the config
- Initialize the new database with
alembic upgrade head
- Run the database migration script
- Start the bridge again
mautrix-googlechat
Welcome to the mautrix-googlechat docs!
Use the sidebar to find the relevant pages. Things that are the same for all bridges, like setting up the bridge, are right below the "Python-based bridges" header. Things specific to mautrix-googlechat are under this page.
These docs are mostly targeted towards people who are hosting the bridge themselves. If you don't want to host it yourself, you can use a public instance. When using public instances, refer to their instructions and support rooms.
- beeper.com (paid service with lots of bridges)
If you run a public instance and wish to list it here, please make a pull request.
Discussion
Matrix room: #googlechat:maunium.net
Authentication
- Open a private chat with the bridge bot. Usually
@googlechatbot:your.server
.- If the bot doesn't accept the invite, see the troubleshooting page
- Send
login
. - Follow the instructions sent by the bot.
- Recent chats should now get portals automatically. Other chats will get portals as you receive messages.
mautrix-twitter
Welcome to the mautrix-twitter docs!
Use the sidebar to find the relevant pages. Things that are the same for all bridges, like setting up the bridge, are right below the "Python-based bridges" header. Things specific to mautrix-twitter are under this page.
These docs are mostly targeted towards people who are hosting the bridge themselves. If you don't want to host it yourself, you can use a public instance. When using public instances, refer to their instructions and support rooms.
- beeper.com (paid service with lots of bridges)
If you run a public instance and wish to list it here, please make a pull request.
Discussion
Matrix room: #twitter:maunium.net
Authentication
- Open a private chat with the bridge bot. Usually
@twitterbot:your.server
.- If the bot doesn't accept the invite, see the troubleshooting page
- Log into Twitter in a private browser window.
- Send
login-cookie
to start the login. - The bot will send you these instructions to extract required cookies.
Follow the steps to log into the bridge:
- Press
F12
to open developer tools. - Select the "Application" (Chrome) or "Storage" (Firefox) tab.
- In the sidebar, expand "Cookies" and select
https://twitter.com
. - In the cookie list, find the
auth_token
row and double click on the value then copy the value and send it to the room. - Repeat the previous step with the
ct0
row.
- Press
- Recent chats should now get portals automatically. Other chats will get portals as you receive messages.
mautrix-signal
Welcome to the mautrix-signal docs!
Use the sidebar to find the relevant pages. Things that are the same for all bridges, like setting up the bridge, are right below the "Python-based bridges" header. Things specific to mautrix-signal are under this page.
These docs are mostly targeted towards people who are hosting the bridge themselves. If you don't want to host it yourself, you can use a public instance. When using public instances, refer to their instructions and support rooms.
- beeper.com (paid service with lots of bridges)
- tchncs.de / #tchncs:tchncs.de
- one.ems.host / #one:element.io (paid service with a few bridges, no end-to-bridge encryption)
If you run a public instance and wish to list it here, please make a pull request.
Discussion
Matrix room: #signal:maunium.net
Authentication
- Open a private chat with the bridge bot. Usually
@signalbot:your.server
- If the bot doesn't accept the invite, see the troubleshooting page
Linking as secondary device
- Go to "Linked Devices" in the Signal app settings and add a new device.
- Send
link
to the bridge bot. - Scan the QR code the bridge sends you.
Registering as the primary device
Note that this method isn't recommended, as it's harder to recover if something goes wrong. When the bridge is linked as a secondary device, it can always be unlinked and relinked if something breaks.
- Send
register <phone>
to the bridge bot. The phone should be in the international format with no spaces. - Once you get the SMS verification code, send it to the bridge.
- To be able to participate in v2 groups, set a profile name with
set-profile-name <name>
.
CAPTCHA
Refer to the signald docs on dealing
with captcha required errors. The bridge supports the same --captcha
parameter as signaldctl, but it must be passed before the phone number instead
of after (e.g. !signal register --captcha signal-recaptcha-v2.03AOLTBLR... +12024561414
).
The signalcaptcha://
prefix must not be included, but everything after it must be.
Signal bridge setup with Docker
Requirements
- Docker
- Docker Compose, or knowledge how to read a docker-compose file and run the docker containers yourself.
- A Matrix homeserver that supports application services (e.g. Synapse)
Setup
- Create a directory for the bridge and cd into it:
mkdir mautrix-signal && cd mautrix-signal
. - Create
docker-compose.yml
that contains something like this:version: "3.7" services: mautrix-signal: container_name: mautrix-signal image: dock.mau.dev/mautrix/signal restart: unless-stopped volumes: - ./bridge:/data - ./signald:/signald depends_on: - signald # If synapse is running outside of docker, you'll need to expose the port. # Note that in most cases you should either run everything inside docker # or everything outside docker, rather than mixing docker things with # non-docker things. #ports: #- "29328:29328" # You'll also probably want this so the bridge can reach Synapse directly # using something like `http://host.docker.internal:8008` as the address: #extra_hosts: #- "host.docker.internal:host-gateway" # If synapse is in a different network, then add this container to that network. # Note the networks object at the bottom too. #networks: #- default # keep the container in the default network too so that the db container is reachable. #- synapsenet signald: container_name: signald image: docker.io/signald/signald restart: unless-stopped volumes: - ./signald:/signald db: image: postgres:13-alpine restart: unless-stopped environment: POSTGRES_USER: mautrixsignal POSTGRES_DATABASE: mautrixsignal POSTGRES_PASSWORD: foobar volumes: - ./db:/var/lib/postgresql/data # When synapse is in a different network (note the networks object in the service too): #networks: # synapsenet: # external: # name: synapsenet
- Run
docker-compose up -d signald
to start signald and make sure it doesn't crash. - Run
docker-compose up mautrix-signal
to make the bridge generate a config file for you, thendocker-compose stop mautrix-signal
so it doesn't try to keep restarting while you're fixing the config. - Update the config to your liking.
- As usual, you'll at least need to change the homeserver settings and add yourself to the permissions section.
- Only postgres is supported as the bridge database, so configure that too.
If you use the docker-compose example above directly,
use
postgres://mautrixsignal:foobar@db/mautrixsignal
as the database URI (but change the password to something else thanfoobar
). - Additionally, you need to update the paths in the
signal
section:socket_path
is/signald/signald.sock
.outgoing_attachment_dir
should be/signald/attachments
(if you can figure out how, you could even use a shared tmpfs for that directory to avoid unencrypted files being temporarily stored on disk).avatar_dir
is/signald/avatars
.
- Generate the appservice registration by running the container again, same command as above.
- Add the path to the registration file to your Synapse's
homeserver.yaml
under theapp_service_config_files
section. - Restart Synapse to apply changes.
- Run
docker-compose up -d
to start the bridge.
Upgrading
docker-compose pull
docker-compose up -d
mautrix-instagram
Welcome to the mautrix-instagram docs!
Use the sidebar to find the relevant pages. Things that are the same for all bridges, like setting up the bridge, are right below the "Python-based bridges" header. Things specific to mautrix-instagram are under this page.
These docs are mostly targeted towards people who are hosting the bridge themselves. If you don't want to host it yourself, you can use a public instance. When using public instances, refer to their instructions and support rooms.
- beeper.com (paid service with lots of bridges)
If you run a public instance and wish to list it here, please make a pull request.
Discussion
Matrix room: #instagram:maunium.net
Authentication
- Open a private chat with the bridge bot. Usually
@instagrambot:your.server
- If the bot doesn't accept the invite, see the troubleshooting page
- Send
login <email> <password>
- If you have 2FA enabled, the bot will ask you to send the 2FA code. If you don't have 2FA enabled, Instagram will likely ask you to confirm the login, in which case the bot will ask you to send the confirmation code.
- Recent chats should now get portals automatically. Other chats will get portals as you receive messages.
Go bridge setup
Please select a bridge above. If you don't select a bridge, you'll have to
manually replace occurrences of $bridge
with the correct name before running
commands.
This page contains instructions for setting up the bridge by running the executable yourself. You may also want to look at the other ways to run the bridge:
- Docker
- YunoHost: mautrix_whatsapp_ynh
- systemd service (at the bottom of this page)
Please note that everything in these docs are meant for server admins who want to self-host the bridge. If you're just looking to use the bridges, check out Beeper, which provides fully managed instances of all of these bridges.
If you need help with setting up the bridge, you can ask in the Matrix room: #$bridge:maunium.net. For help with setting up other parts like the homeserver that aren't the bridge, refer to their documentation to find support rooms.
Requirements
- A Matrix homeserver that supports application services (e.g. Synapse). You need access to register an appservice, which usually involves editing the homeserver config file.
- A PostgreSQL server, v10 or higher (which you should already have for Synapse).
- Make sure you don't share databases between unrelated programs. Shared postgres instance is fine, but shared database is not.
- mautrix-whatsapp: A WhatsApp client running on a phone (both physical and virtual phones work).
- mautrix-whatsapp: ffmpeg (if you want to send gifs from Matrix).
If you want to compile the bridge manually (which is not required), you'll also need:
- Go 1.19.1+ (download & installation instructions at https://go.dev/doc/install).
- libolm3 with dev headers and a C/C++ compiler (if you want end-to-bridge encryption).
Installation
You may either compile the bridge manually or download a prebuilt executable from the mau.dev CI or GitHub releases. Prebuilt executables are the simplest option, as they don't require having Go nor libolm installed.
Downloading a prebuilt executable from CI
- Go to https://mau.dev/mautrix/$bridge/-/pipelines?scope=branches&page=1
- Find the entry for the
master
branch, click the download button on the right-hand side in the list and choose the architecture you want. - Extract the downloaded zip file into a new directory.
Downloading a release
- Go to https://github.com/mautrix/$bridge/releases
- Download the binary for the architecture you want and save it in a new directory.
Compiling manually
- Clone the repo with
git clone https://github.com/mautrix/$bridge.git mautrix-$bridge
- Enter the directory (
cd mautrix-$bridge
) - Run
./build.sh
to fetch Go dependencies and compile (build.sh
will simply callgo build
with some additional flags).- If you want end-to-bridge encryption, make sure you have a C/C++ compiler
and the Olm dev headers (
libolm-dev
on debian-based distros) installed. Note that libolm3 is required, which means you have to use backports on Debian stable. - If not, use
./build.sh -tags nocrypto
to disable encryption.
- If you want end-to-bridge encryption, make sure you have a C/C++ compiler
and the Olm dev headers (
Configuring and running
- Copy
example-config.yaml
toconfig.yaml
- Update the config to your liking. You'll at least need to change the homeserver settings, database address, and bridge permissions. If you miss something that's required, the bridge will refuse to start and tell you what's missing.
- Generate the appservice registration file by running
./mautrix-$bridge -g
.- You can use the
-c
and-r
flags to change the location of the config and registration files. They default toconfig.yaml
andregistration.yaml
respectively.
- You can use the
- Register the bridge on your homeserver (see Registering appservices).
- Run the bridge with
./mautrix-$bridge
.
Updating
If you compiled manually, pull changes with git pull
and recompile with
./build.sh
.
If you downloaded a prebuilt executable, simply download a new one and replace the old one.
Finally, start the bridge again.
systemd service
- Create a user for the bridge:
$ sudo adduser --system mautrix-$bridge --home /opt/mautrix-$bridge
- Follow the normal setup instructions above. Make sure you use that user and home directory for the bridge.
- Create a systemd service file at
/etc/systemd/system/mautrix-$bridge.service
:[Unit] Description=mautrix-$bridge bridge [Service] Type=exec User=mautrix-$bridge WorkingDirectory=/opt/mautrix-$bridge ExecStart=/opt/mautrix-$bridge/mautrix-$bridge Restart=on-failure RestartSec=30s # Optional hardening to improve security ReadWritePaths=/opt/mautrix-$bridge NoNewPrivileges=yes MemoryDenyWriteExecute=true PrivateDevices=yes PrivateTmp=yes ProtectHome=yes ProtectSystem=strict ProtectControlGroups=true RestrictSUIDSGID=true RestrictRealtime=true LockPersonality=true ProtectKernelLogs=true ProtectKernelTunables=true ProtectHostname=true ProtectKernelModules=true PrivateUsers=true ProtectClock=true SystemCallArchitectures=native SystemCallErrorNumber=EPERM SystemCallFilter=@system-service [Install] WantedBy=multi-user.target
mautrix-whatsapp
Welcome to the mautrix-whatsapp docs!
Use the sidebar to find the relevant pages. Things that are the same for all bridges, like setting up the bridge, are right below the "Go-based bridges" header. Things specific to mautrix-whatsapp are under this page.
These docs are mostly targeted towards people who are hosting the bridge themselves. If you don't want to host it yourself, you can use a public instance. When using public instances, refer to their instructions and support rooms.
- beeper.com (paid service with lots of bridges)
- tchncs.de / #tchncs:tchncs.de
- one.ems.host / #one:element.io (paid service with a few bridges, no end-to-bridge encryption)
If you run a public instance and wish to list it here, please make a pull request.
Discussion
Matrix room: #whatsapp:maunium.net
In case you need to upload your logs somewhere, be aware that they contain your
contacts' and your phone numbers. Strip them out with | sed -r 's/[0-9]{10,}/📞/g'
Android VM setup (not recommended)
This page documents how to setup WhatsApp in an Android Virtual Machine. It could be useful if you cannot or don't want to run WhatsApp on a mobile phone.
Running in a virtual machine is more suspicious and increases the risk of getting banned. A physical phone is recommended.
Requirements
You'll need a working Android SDK. You can use the Android Studio suite or only the command-line tools.
Currently the Android SDK appears to only work with OpenJDK8 (not 11), which will need to be installed.
WhatsApp in the Android VM will need to scan a QR-code via webcam. We can do this by passing the emulator a real webcam (which needs to be able to see the emulator screen) or a virtual one (e.g. v4l2loopback).
Android Virtual Device
Let's create an AVD (Android Virtual Device), get its webcam working and install WhatsApp.
Create the AVD
WhatsApp currently requires Android 2.3.3 (API 10) or newer. If you wish to install WhatsApp through the play store, choose a System Image supporting Google APIs.
The AVD will be created in ~/.android/avd/
, regardless of the method you use
to create it.
Using Android Studio
Android Studio offers an AVD Manager interface to create, configure and run AVDs.
Via command line
It's also possible to create an emulated android device from command line, using avdmanager from the Android SDK:
Install the required SDK components
Change the version and architecture as required. If your host has KVM support you should use the x86 target. If you don't have KVM support (running in certain VPS systems) then you will need to use the ARM targets.
./tools/bin/sdkmanager --install platform-tools emulator
./tools/bin/sdkmanager --install "platforms;android-24"
./tools/bin/sdkmanager --install "system-images;android-24;default;armeabi-v7a"
Once you have the SDK setup you can create a VM.
./tools/bin/avdmanager create avd -n AVD_NAME -k SDK_ID
e.g.:
./tools/bin/avdmanager create avd -n MyWhatsAppVM -k "system-images;android-24;default;armeabi-v7a"
or when using KVM (includes Play Store):
./tools/bin/avdmanager create avd -n MyWhatsAppVM -k "system-images;android-28;google_apis_playstore;x86"
Run the AVD using the Android Emulator:
./emulator/emulator -show-kernel -no-boot-anim -avd AVD_NAME
Set up the webcam
Android Emulator seems to support different ways to feed custom images/videos to
the Android Webcam, but somehow the only one that worked for me is passing it
the host's camera (i.e. using webcam0
camera mode).
webcam0
seems to always be connected to the device /dev/video0
. In case you
wish to use a different device (e.g. /dev/video2
), rename it to /dev/video0
:
# needed if you want to feed /dev/video2 to the AVD
sudo mv /dev/video0 /dev/video0.original
sudo mv /dev/video2 /dev/video0
Set the back-camera mode to webcam0
, either using the AVD Manager GUI (enable
Show Advanced Settings
) or by running the emulator from command line:
./emulator/emulator -avd AVD_NAME -camera-back webcam0
Use v4l2loopback
to create a virtual camera
Install the v4l2loopback
module and load it:
modprobe v4l2loopback
This should create a new /dev/video*
file. If needed, rename it as /dev/video0
.
Feed your desktop into this virtual webcam, e.g. using:
ffmpeg -f x11grab -s 640x480 -i :0.0+10,20 -vf format=pix_fmts=yuv420p -f v4l2 /dev/video0
You can test whether it's working by watching your webcam
(e.g. with mplayer tv:// -tv driver=v4l2:device=/dev/video0
).
The AVD's webcam should now show a piece of your desktop. When mautrix-whatsapp (or WhatsApp Web) shows you the QR-code, just move its window onto the shared desktop area.
Boot the AVD
You can boot the AVD using the AVD Manager GUI, or calling the emulator via command line:
./emulator/emulator -avd AVD_NAME [options]
Some useful options include:
-no-audio
and-no-window
, to disable audio and video for the VM. With these the emulator can run headless.-show-kernel
, display the console boot text instead of showing the boot GUI-no-snapshot
, to cold boot the AVD (i.e. it will ignore some cache).-memory MB
, to reduce the amount of RAM passed to the AVD. Unfortunately the emulator will force a minimum amount.
Install WhatsApp
WhatsApp will only work with your phone number on a device per time: when you log in on your AVD, the other devices will disconnect. If you install WhatsApp on an AVD and copy such AVD, both copies will be able to run WhatsApp (although not at the same time!)
WhatsApp can be installed using Google Play, if available, or with an APK. In
the latter case, just drag'n'drop the APK on the emulator's window or run
adb install APK_FILE
.
In the 'Chats screen' goto 'Menu' > 'WhatsApp Web'. You can follow the instructions and use WhatsApp Web to verify whether all is working.
You can now proceed to link your virtual android to the bridge as described on the authentication Page.
NOTE: The bridge will cycle through multiple QR codes, you have to have everything ready to go. You won't have time to copy/paste images so you will need the VM and the Matrix client running on the same desktop.
After installation has finished ensure you open Android settings -> "Battery" -> "All Apps" -> find WhatsApp and choose: "Do not optimize".
Running Headless
Once everything is working, you can run the Android emulator headless, and even copy it to a server or whatever.
Make sure that all the software we need (Android SDK, Emulator, system images etc) is installed on the target host.
Copy your AVD over there (from ~/.android/avd/AVD_NAME.*
on your system to the
~/.android/avd/
of the target host).
Run the emulator headless:
./emulator/emulator -avd AVD_NAME -no-audio -no-window [options]
If your AVD goes into sleep-mode or becomes unresponsive, you can try to reboot
it or to start WhatsApp main activity running
am start -n 'com.whatsapp/.HomeActivity'
on your AVD
(or e.g. adb [-s DEVICE_SERIAL] shell am start -n 'com.whatsapp/.HomeActivity'
directly on your shell).
Required packages
Here a list of the packages you'll need to install on various Linux distributions to make everything work.
Arch Linux
Either install android-studioAUR or:
- android-tools
- android-sdkAUR
- android-emulatorAUR
- android-x86-system-image-XXAUR (replace
XX
with the system image you wish to use)
You might want to choose jdk8-openjdk
as java-environment, as newer JDKs
seem to have problems with the Android stuff.
Note that android-studio and the other packages aren't fully compatible: the
system image path will differ slightly and you'll need to fix it in the AVD
config.ini
files: image.sysdir.1
should be something like
system-images/android-15/default/x86/
for Android Studio images, and
system-images/android-15/x86/
for AUR system images. The emulator will
otherwise fail printing Cannot find AVD system path. Please define ANDROID_SDK_ROOT
.
Install v4l2loopback-dkms-gitAUR to use v4l2loopback.
Authentication
- Open a private chat with the bridge bot. Usually
@whatsappbot:your.server
- If the bot doesn't accept the invite, see the troubleshooting page
- Send
login
to start the login. - Log in by scanning the QR code. If the code expires before you scan it, the
bridge will send an error to notify you.
- Open WhatsApp on your phone.
- Tap Menu
or Settings
and select Linked devices.
- Point your phone at the image sent by the bot to capture the code.
- Finally, the bot should inform you of a successful login and the bridge should start creating portal rooms for your recent WhatsApp groups and private chats.
Please note that the bridge uses the web API. Prior to v0.2.0 and the multidevice update, your phone had to be connected to the internet for the bridge to work. After v0.2.0, it's enough if the phone is connected at least once every 2 weeks. If the phone is offline for >2 weeks, linked devices will become disconnected: https://faq.whatsapp.com/general/download-and-installation/about-linked-devices. The bridge will warn you if it doesn't receive any data from the phone in over 12 days.
N.B. WhatsApp is known to ban accounts that are too suspicious. Just using the bridge shouldn't cause any bans, but getting banned is more likely when combining the bridge with other suspicious activity (running WhatsApp in an Android emulator, using VoIP numbers, using a newly created account, initiating DMs to non-contacts, etc).
Logging out
Simply run the logout
management command.
mautrix-discord
Welcome to the mautrix-discord docs!
Use the sidebar to find the relevant pages. Things that are the same for all bridges, like setting up the bridge, are right below the "Go-based bridges" header. Things specific to mautrix-discord are under this page.
These docs are mostly targeted towards people who are hosting the bridge themselves. If you don't want to host it yourself, you can use a public instance. When using public instances, refer to their instructions and support rooms.
- beeper.com (paid service with lots of bridges)
If you run a public instance and wish to list it here, please make a pull request.
Discussion
Matrix room: #discord:maunium.net
Authentication
- Open a private chat with the bridge bot. Usually
@discordbot:your.server
- If the bot doesn't accept the invite, see the troubleshooting page
- Follow one of the three instructions below.
QR login
QR login is more convenient, but requires having the Discord mobile app installed, and may encounter CAPTCHAs which are currently not supported by the bridge.
- Send
login-qr
to start the login. - Log in by scanning the QR code with a Discord mobile app.
- After scanning the code, you'll need to approve the login on the mobile app. See the official docs for more info.
- The app can be uninstalled afterwards.
- If you encounter a bad request error saying something about a captcha, you'll have to use token login. Otherwise the login should be successful.
Token login
You can also log in by logging in manually and providing the access token to the bridge.
- Log in to Discord in a browser. A private window is recommended so you can easily make the browser forget the token without invalidating it.
- Press F12 (or Cmd+Shift+I on Mac) to open developer tools.
- Select the "Network" tab and filter for
api
. - Press F5 (or Cmd+R on Mac) to reload the page.
- Pick any successful request (e.g. the
library
request). Scroll down to "Request Headers" and find theAuthorization
header. Right-click the entry and choose copy value. - Send
login-token user <token>
to the bot (replacing<token>
with the copied value). - (Close the private window)
Bot token login
If you don't want to use a real account, you can also log in as a bot.
- Create an application on https://discord.com/developers/applications.
- In the "Bot" section, add a bot and copy the token.
- Enable "server members intent" and "message content intent" under the "Privileged Gateway Intents" section.
- Send
login-token bot <token>
- To add your bot to a guild, go to OAuth2 -> URL Generator, select "bot"
under scopes and select the permissions to grant. The generated URL can then
be used to add the bot to a guild.
- At least "Send Messages", "Create Public Threads", "Send Messages in Threads", "Read Message History" and "Add Reactions" are recommended.
- If you're the guild admin, you can just choose "Administrator" for the bot and not worry about exact permissions.
After a successful login, the bridge will create portals for some recent DMs
(some is defined by startup_private_channel_create_limit
in the bridge config).
To bridge guilds, use the guilds
command.
Relaying with webhooks
New in version 0.2.0
The bridge supports using Discord's webhook feature to relay messages from Matrix users who haven't logged into the bridge.
Webhook relays can be used regardless of how you logged into Discord, a bot is not required. However, in the future the bridge may include additional relay integration using a bot.
Setup
To enable relaying in a room, use !discord set-relay
. The command requires a
parameter, which can either be --create [name]
or --url <url>
.
!discord set-relay --create
will create a new webhook. You must be logged into the bridge as a user or bot that has privileges to create webhooks in on the Discord side.- You can optionally pass a name for the webhook after the command,
e.g.
!discord set-relay --create matrix bridge
. The default name is "mautrix". Note that the name may not contain "discord".
- You can optionally pass a name for the webhook after the command,
e.g.
!discord set-relay --url https://discord.com/api/webhooks/...
will use the given webhook URL for relaying.- You can optionally specify a room ID before
--url
to run the command in a private room (and avoid leaking the webhook secret to everyone else in the room being bridged), e.g.!discord set-relay !26DmcJd3cQ...:example.com --url https://discord.com/...
- You can optionally specify a room ID before
Direct media access
New in version 0.4.0
To avoid spamming your homeserver's media repository with all files from
Discord, the bridge has an option to generate fake mxc://
URIs that contain
the Discord media ID. The media repo or your reverse proxy can then handle
those URIs specially to fetch content directly from the Discord CDN.
To enable this mode, set bridge
-> media_patterns
-> enabled
to true
in the bridge config. You can then configure each of the patterns or leave the
defaults.
Ways to use patterns
Default pattern and MSC3860-compatible media repo
If your media repo supports MSC3860, you can use the default patterns out of the box with no modifications. Your media repo will act like discord-media.mau.dev is a federated Matrix server, so when your client requests Discord media, your media repo will ask discord-media.mau.dev, which redirects to cdn.discordapp.com. Your media repo then downloads the media and caches it as remote media (like it does for all federated media).
As of writing, normal Matrix servers don't support MSC3860 yet, but they likely will in the future once the MSC passes.
The software on discord-media.mau.dev is just a Caddy instance with the first example config below, plus a static .well-known file to redirect federation to 443. You can find the raw config at mau.dev/maunium/caddy.
Redirect in reverse proxy
You can also configure your reverse proxy to redirect mxc://discord-media.mau.dev/*
downloads directly to cdn.discordapp.com. This method doesn't involve your
media repo at all, so it already works with most clients. However, it won't
work with servers that don't support MSC3860, as they'd still try to connect to
discord-media.mau.dev, which may be a problem if you want to use your bridge in
federated rooms. Additionally, you may encounter some CORS issues with this
method as cdn.discordapp.com doesn't provide CORS headers for all files (like
webp images and non-inline documents)
Caddy config example
matrix.example.com {
handle /_matrix/media/*/download/discord-media.mau.dev/* {
# The redirect must have CORS headers to let web clients follow it.
header Access-Control-Allow-Origin *
# Need to use a route directive to make the uri mutations apply before redir
route {
# Remove path prefix
uri path_regexp ^/_matrix/media/.+/download/discord-media\.mau\.dev/ /
# The mxc patterns use | instead of /, so replace it first turning the path into attachments/1234/5678/filename.png
uri replace "%7C" /
# Then redirect to cdn.discordapp.com/attachments/1234/5678/filename.png with HTTP 307
redir https://cdn.discordapp.com{uri} 307
}
}
# Special-case stickers because they don't have CORS headers on cdn.discordapp.com for some reason
handle /_matrix/media/*/download/discord-media.mau.dev/stickers|* {
header Access-Control-Allow-Origin *
route {
uri path_regexp ^/_matrix/media/.+/download/discord-media\.mau\.dev/ /
uri replace "%7C" /
redir https://media.discordapp.net{uri} 307
}
}
# Do the same for thumbnails, but redirect to media.discordapp.net (which is Discord's thumbnailing server, and happens to use similar width/height params as Matrix)
# Alternatively, you can point this at cdn.discordapp.com too. Clients shouldn't mind even if they get a bigger image than they asked for.
handle /_matrix/media/*/thumbnail/discord-media.mau.dev/* {
header Access-Control-Allow-Origin *
route {
uri path_regexp ^/_matrix/media/.+/thumbnail/discord-media\.mau\.dev/ /
uri replace "%7C" /
redir https://media.discordapp.net{uri} 307
}
}
# The usual proxying to your homeserver
handle /_matrix/* {
reverse_proxy http://localhost:8008
}
}
Nginx config example
server {
listen 443;
server_name matrix.example.com;
# ... usual /_matrix location block and other stuff ...
location ~ ^/_matrix/media/(?:v3|r0)/download/discord-media.mau.dev/attachments\|([0-9]+)\|([0-9]+)\|(.+)$ {
add_header Access-Control-Allow-Origin *;
return 307 https://cdn.discordapp.com/attachments/$1/$2/$3;
}
location ~ ^/_matrix/media/(?:v3|r0)/download/discord-media.mau.dev/emojis\|(.+)$ {
add_header Access-Control-Allow-Origin *;
return 307 https://cdn.discordapp.com/emojis/$1;
}
location ~ ^/_matrix/media/(?:v3|r0)/download/discord-media.mau.dev/stickers\|(.+)$ {
add_header Access-Control-Allow-Origin *;
# Stickers don't have CORS headers on cdn.discordapp.com for some reason, so always use media.
return 307 https://media.discordapp.net/stickers/$1;
}
location ~ ^/_matrix/media/(?:v3|r0)/download/discord-media.mau.dev/avatars\|([0-9]+)\|(.+)$ {
add_header Access-Control-Allow-Origin *;
return 307 https://cdn.discordapp.com/avatars/$1/$2;
}
# Thumbnails (optional-ish)
location ~ ^/_matrix/media/(?:v3|r0)/thumbnail/discord-media.mau.dev/attachments\|([0-9]+)\|([0-9]+)\|(.+)$ {
add_header Access-Control-Allow-Origin *;
return 307 https://media.discordapp.net/attachments/$1/$2/$3?$args;
}
location ~ ^/_matrix/media/(?:v3|r0)/thumbnail/discord-media.mau.dev/emojis\|(.+)$ {
add_header Access-Control-Allow-Origin *;
return 307 https://media.discordapp.net/emojis/$1?$args;
}
location ~ ^/_matrix/media/(?:v3|r0)/thumbnail/discord-media.mau.dev/stickers\|(.+)$ {
add_header Access-Control-Allow-Origin *;
return 307 https://media.discordapp.net/stickers/$1?$args;
}
location ~ ^/_matrix/media/(?:v3|r0)/thumbnail/discord-media.mau.dev/avatars\|([0-9]+)\|(.+)$ {
add_header Access-Control-Allow-Origin *;
return 307 https://media.discordapp.net/avatars/$1/$2?$args;
}
}
Proxy in reverse proxy
If you want bridged media to work over federation without MSC3860, you can change discord-media.mau.dev to your own server name, and have your reverse proxy actually proxy the downloads instead of just redirecting to cdn.discordapp.com. That way it'll work with all existing servers and clients. The downside of this method is the higher bandwidth use compared to redirecting, and theoretical abuse vectors for spamming the Discord CDN through your server.
When using this example, change discord-media.mau.dev/
in the patterns to
example.com/discord_
(replacing example.com
with your own domain). The
discord_
prefix is there so that other media on your domain will still work
normally.
Caddy config example
matrix.example.com {
handle /_matrix/media/*/download/example.com/discord_* {
header Access-Control-Allow-Origin *
# Remove path prefix
uri path_regexp ^/_matrix/media/.+/download/example\.com/discord_ /
# The mxc patterns use | instead of /, so replace it first turning it into attachments/1234/5678/filename.png
uri replace "%7C" /
reverse_proxy {
# reverse_proxy automatically includes the uri, so no {uri} at the end
to https://cdn.discordapp.com
# Caddy doesn't set the Host header automatically when reverse proxying
# (because usually reverse proxies are local and don't care about Host headers)
header_up Host cdn.discordapp.com
}
}
# Do the same for thumbnails, but redirect to media.discordapp.net (which is Discord's thumbnailing server, and happens to use similar width/height params as Matrix)
# Alternatively, you can point this at cdn.discordapp.com too. Clients shouldn't mind even if they get a bigger image than they asked for.
handle /_matrix/media/*/thumbnail/example.com/discord_* {
header Access-Control-Allow-Origin *
uri path_regexp ^/_matrix/media/.+/thumbnail/example\.com/discord_ /
uri replace "%7C" /
reverse_proxy {
to https://media.discordapp.net
header_up Host media.discordapp.net
}
}
handle /_matrix/* {
reverse_proxy http://localhost:8008
}
}
Nginx config example
server {
listen 443;
server_name matrix.example.com;
# ... usual /_matrix location block and other stuff ...
# You may need to configure a resolver for nginx to be able to resolve cdn.discordapp.com
#resolver 8.8.8.8;
location ~ ^/_matrix/media/(?:v3|r0)/download/discord-media.mau.dev/attachments\|([0-9]+)\|([0-9]+)\|(.+)$ {
add_header Access-Control-Allow-Origin *;
proxy_set_header Host cdn.discordapp.com;
proxy_pass https://cdn.discordapp.com/attachments/$1/$2/$3;
}
location ~ ^/_matrix/media/(?:v3|r0)/download/discord-media.mau.dev/emojis\|(.+)$ {
add_header Access-Control-Allow-Origin *;
proxy_set_header Host cdn.discordapp.com;
proxy_pass https://cdn.discordapp.com/emojis/$1;
}
location ~ ^/_matrix/media/(?:v3|r0)/download/discord-media.mau.dev/stickers\|(.+)$ {
add_header Access-Control-Allow-Origin *;
proxy_set_header Host cdn.discordapp.com;
proxy_pass https://cdn.discordapp.com/stickers/$1;
}
location ~ ^/_matrix/media/(?:v3|r0)/download/discord-media.mau.dev/avatars\|([0-9]+)\|(.+)$ {
add_header Access-Control-Allow-Origin *;
proxy_set_header Host cdn.discordapp.com;
proxy_pass https://cdn.discordapp.com/avatars/$1/$2;
}
# Thumbnails (optional-ish)
location ~ ^/_matrix/media/(?:v3|r0)/thumbnail/discord-media.mau.dev/attachments\|([0-9]+)\|([0-9]+)\|(.+)$ {
add_header Access-Control-Allow-Origin *;
proxy_set_header Host cdn.discordapp.com;
proxy_pass https://media.discordapp.net/attachments/$1/$2/$3?$args;
}
location ~ ^/_matrix/media/(?:v3|r0)/thumbnail/discord-media.mau.dev/emojis\|(.+)$ {
add_header Access-Control-Allow-Origin *;
proxy_set_header Host cdn.discordapp.com;
proxy_pass https://media.discordapp.net/emojis/$1?$args;
}
location ~ ^/_matrix/media/(?:v3|r0)/thumbnail/discord-media.mau.dev/stickers\|(.+)$ {
add_header Access-Control-Allow-Origin *;
proxy_set_header Host cdn.discordapp.com;
proxy_pass https://media.discordapp.net/stickers/$1?$args;
}
location ~ ^/_matrix/media/(?:v3|r0)/thumbnail/discord-media.mau.dev/avatars\|([0-9]+)\|(.+)$ {
add_header Access-Control-Allow-Origin *;
proxy_set_header Host cdn.discordapp.com;
proxy_pass https://media.discordapp.net/avatars/$1/$2?$args;
}
}
mautrix-slack
Welcome to the mautrix-slack docs!
Use the sidebar to find the relevant pages. Things that are the same for all bridges, like setting up the bridge, are right below the "Go-based bridges" header. Things specific to mautrix-slack are under this page.
These docs are mostly targeted towards people who are hosting the bridge themselves. If you don't want to host it yourself, you can use a public instance. When using public instances, refer to their instructions and support rooms.
- beeper.com (paid service with lots of bridges)
If you run a public instance and wish to list it here, please make a pull request.
Discussion
Matrix room: #slack:maunium.net
Authentication
- Open a private chat with the bridge bot. Usually
@slackbot:your.server
.- If the bot doesn't accept the invite, see the troubleshooting page
Password login
Password login supports all Slack features, except portals for Slack conversations will not be created immediately after login. If your Slack account does not have a password you need to use token login or add a password to your account.
- Send the command
login-password <email address> <slack team domain> <password>
, for examplelogin-password me@email.com workplacechat.slack.com hunter2
.
Password login isn't guaranteed to always be fully supported, but you can switch to token-based login at any time afterwards by following the instructions in the Token login section without signing out.
Token login
Token login works for any Slack account and fully supports all Slack features.
- Login to the Slack web app in a browser, and acquire the authentication token and
d
cookie from inside the app.- The token starts with
xoxc-
and can be found using the browser devtools, in the app's local storage inside thelocalConfig_v2
object, asteams['your team ID'].token
. - The cookie is named
d
, it starts withxoxd-
and can be found in the cookies section in the devtools.
- The token starts with
- Send the command
login-token <token> <cookie>
, for examplelogin-token xoxc-tokengoeshere xoxd-cookiegoeshere
After login using a token, all your joined channels will automatically be bridged into Matrix, but DMs will only appear once you receive messages in them.
mautrix-imessage
Welcome to the mautrix-imessage docs!
mautrix-imessage is a Matrix-iMessage puppeting bridge. The bridge has three different ways to connect to iMessage:
- Normal Mac. Built into mautrix-imessage. Uses AppleScript to send, reads the iMessage SQLite database to receive, and uses Contacts.framework for contact list access.
- Mac with SIP disabled. Uses Barcelona to hook into Apple's private iMessage frameworks on a Mac. Requires disabling SIP and AMFI to be able to hook into private frameworks.
Jailbroken iOS. Uses Brooklyn to hook into Apple's private iMessage frameworks on a jailbroken iOS device.32-bit support has been deprecated, Barcelona can be used on newer iOS devices.- Additionally, there's android-sms, an Android app that implements the same IPC protocol as Brooklyn and Barcelona to bridge SMS from an Android phone.
You can find setup instructions for each of the connectors in the sidebar.
This bridge essentially has to be self-hosted, so you likely won't find public instances on normal Matrix servers, but Beeper does offer hosted iMessage bridges (using the Barcelona connector) and the Beeper Android app has the android-sms bridge built in.
Discussion
Matrix room: #imessage:maunium.net
iMessage bridge setup (macOS)
Please note that everything in these docs are meant for server admins who want to self-host the bridge. If you're just looking to use the bridges, check out Beeper, which provides fully managed instances of all of these bridges.
Requirements
- A computer running a reasonably new version of macOS.
- The bridge requires full disk access in privacy settings to read your chat database.
- A Matrix homeserver that supports application services (e.g. Synapse). You need access to register an appservice, which usually involves editing the homeserver config file.
- A websocket proxy to receive appservice transactions.
If you want to compile the bridge manually (which is not required), you'll also need:
- Go 1.19+ (download & installation instructions at https://go.dev/doc/install).
- libolm3 with dev headers (
brew install libolm
). - Optionally libheif with dev headers for heif -> jpeg conversion (
brew install libheif
).
Installation
You may either compile the bridge manually or download a prebuilt executable from the mau.dev CI.
Compiling manually
- Clone the repo with
git clone https://github.com/mautrix/imessage.git
. - Enter the directory (
cd mautrix-imessage
). - Run
./build.sh
to fetch Go dependencies and compile (build.sh
will simply callgo build
with some additional flags).
Downloading a prebuilt executable
- Go to https://mau.dev/mautrix/imessage/-/pipelines?scope=branches&page=1
- Find the entry for the
master
branch and click the download button on the right-hand side in the list.- There are three entries: universal, arm64 (Apple Silicon) and amd64 (Intel). You can either pick universal, or the specific architecture depending on what Mac you have.
- Extract the downloaded zip file into a new directory.
Configuring and running
- Copy
example-config.yaml
toconfig.yaml
- Update the config to your liking.
- You need to make sure that the
address
anddomain
field point to your homeserver. - You will also need to add your user ID to the
bridge
section.
- You need to make sure that the
- Generate the appservice registration file by running
./mautrix-imessage -g
.- You can use the
-c
and-r
flags to change the location of the config and registration files. They default toconfig.yaml
andregistration.yaml
respectively.
- You can use the
- Set up mautrix-wsproxy.
- Update your registration file so the
url
field points to wsproxy (e.g.http://localhost:29331
, this is where your homeserver reaches wsproxy), and make sure thewebsocket_proxy
field in the bridge config also points to wsproxy (e.g.ws://matrix.example.com:29331
, where the bridge reaches wsproxy). - Register the bridge on your homeserver (see Registering appservices).
- Run the bridge with
./mautrix-imessage
. - If/when the bridge fails to initialize the iMessage connector with the
operation not permitted
error, go to System Preferences -> Security & Privacy -> Privacy -> Full Disk Access and grant access to the terminal you're running the bridge in.
iMessage bridge setup (macOS without SIP)
Please note that everything in these docs are meant for server admins who want to self-host the bridge. If you're just looking to use the bridges, check out Beeper, which provides fully managed instances of all of these bridges.
Requirements
- A computer running macOS 11 or higher, with SIP and AMFI disabled (see instructions below).
- A Matrix homeserver that supports application services (e.g. Synapse). You need access to register an appservice, which usually involves editing the homeserver config file.
- A websocket proxy to receive appservice transactions.
If you want to compile the bridge manually (which is not required), you'll also need:
- Go 1.19+ (download & installation instructions at https://go.dev/doc/install).
- libolm3 with dev headers (
brew install libolm
). - Optionally libheif with dev headers for heif -> jpeg conversion (
brew install libheif
). - Xcode 14.2+ if you want to build Barcelona yourself.
Installation
This form of the bridge consists of two components: Barcelona for connecting to iMessage and mautrix-imessage for connecting to Matrix. mautrix-imessage will run Barcelona as a subprocess and they communicate over stdio.
You may either compile the bridge and Barcelona manually, or download prebuilt executables from the mau.dev CI and GitHub actions respectively.
Because Barcelona hooks into Apple's private APIs, you must disable SIP (System Integrity Protection) and AMFI (Apple Mobile File Integrity) on the Mac for it to work. Disabling SIP will make your Mac less secure, so you should only do it on a Mac that you won't use for anything else.
Compiling manually
- Clone the repo with
git clone https://github.com/mautrix/imessage.git
. - Enter the directory (
cd mautrix-imessage
). - Run
./build.sh
to fetch Go dependencies and compile (build.sh
will simply callgo build
with some additional flags). - Refer to the Barcelona build instructions for building Barcelona.
Downloading prebuilt executables
- Go to https://mau.dev/mautrix/imessage/-/pipelines?scope=branches&page=1
- Find the entry for the
master
branch and click the download button on the right-hand side in the list and choose "build universal". - Extract the downloaded zip file into a new directory.
- Download
darwin-barcelona-mautrix
from https://github.com/beeper/barcelona/actions (latest direct download).
Disabling SIP and AMFI
Disabling SIP and AMFI will make your Mac significantly less secure.
- Boot into recovery mode (hold Command+R while booting) and open a terminal
- Run
csrutil disable
to disable SIP - Run
nvram boot-args="amfi_get_out_of_my_way=0x1"
to disable AMFI- If you run other things like Electron apps on the Mac (which you definitely
should not), you may want to add
ipc_control_port_options=0
to prevent those from breaking.
- If you run other things like Electron apps on the Mac (which you definitely
should not), you may want to add
If you are running macOS in a VM (e.g. through OSX-KVM) you may need to
disable AMFI with a boot option. Assuming you are using OSX-KVM and OpenCore,
open the config.plist
(in EFI/OC/config.plist
) and change the key
boot-args
to add amfi_get_out_of_my_way=0x1
:
<key>boot-args</key>
<string>-v keepsyms=1 tlbto_us=0 vti=9 amfi_get_out_of_my_way=0x1</string>
You can also refer to Apple's official documentation on disabling SIP.
Configuring and running
- Follow steps 1-6 from the normal macOS setup
- Install Barcelona's com.apple.security.xpc.plist to
/Library/Preferences/com.apple.security.xpc.plist
- In the
imessage
section of the config, changeplatform
tomac-nosip
and setimessage_rest_path
to the path to thedarwin-barcelona-mautrix
executable you downloaded or compiled. - Run the bridge with
./mautrix-imessage
.
iMessage bridge setup (iOS)
DEPRECATED
mautrix-imessage has dropped support for 32-bit iOS devices, so this Brooklyn-based bridge setup is now deprecated. Newer iOS-based devices can use Barcelona (which is meant for macOS without SIP, but works on jailbroken iOS). However, instructions for Barcelona on iOS are not yet available here.
If you still want to use Brooklyn with an old iOS device, the last commit that supports Go 1.14 and 32-bit iOS is 31bc6e28
Please note that everything in these docs are meant for server admins who want to self-host the bridge. If you're just looking to use the bridges, check out Beeper, which provides fully managed instances of all of these bridges.
Requirements
- A jailbroken iOS device, minimum and recommended is iPhone 4S with iOS 8.4(.1).
- A Matrix homeserver that supports application services (e.g. Synapse). You need access to register an appservice, which usually involves editing the homeserver config file.
- A websocket proxy to receive appservice transactions.
Installation
The bridge consists of two components: Brooklyn for connecting to iMessage and mautrix-imessage for connecting to Matrix. The Brooklyn app runs mautrix-imessage as a subprocess and they communicate over stdio.
The recommended way to install the app is getting a precompiled build from the Cydia repo. You can technically also compile everything yourself, but that is less documented.
Compiling manually
There are instructions for compiling Brooklyn in the GitHub repo.
Compiling mautrix-imessage for darwin/armv7 is more complicated and not currently documented. For more recent devices (i.e. armv8/arm64), it should be as simple as compiling mautrix-imessage on a Mac with Apple Silicon.
Precompiled builds
You can get the Brooklyn app with a bundled mautrix-imessage from the Cydia repo. The repo is currently available at http://maunium.mau.life/brooklyn/ (repo URL subject to change). After adding the repo in Cydia, simply install the "Brooklyn" package from the repo.
Configuring and running
- Get the example config and fill it out. You'll at least need to:
- Fill everything in the
homeserver
section. - Set
bridge
->user
to your MXID. - Change
imessage
->platform
toios
. - Generate random tokens for the
as_token
andhs_token
fields.
- Fill everything in the
- Get the example registration and copy the relevant values from the config.
- Set up mautrix-wsproxy.
- Register the bridge on your homeserver (see Registering appservices).
- Serve the config file with the webserver of your choice. It's recommended
to use a random file name or add HTTP basic auth to prevent other people
from reading your config.
- HTTP basic auth documentation: Caddy, nginx, Apache
- N.B. Due to a bug in Brooklyn, the URL must be lowercase.
- Generate a QR code with the URL to your config
(e.g.
echo -n https://user:pass@example.com/your-config.yaml | qrencode -t ansiutf8
). - Scan the QR code with Brooklyn.
Troubleshooting
The brooklyn app keeps showing the QR Code reader popup
- Connect your iPhone to a Mac and open the Console app to see logs
- Filter for "Brooklyn" to see logs
- If you see
Brooklyn mautrix-imessage sent error:Failed to download config: failed to open config.yaml for writing config: open config.yaml: permission denied
, use the following to mitigate:- install OpenSSH via Cydia
- ssh to the iPhone (find out IP via settings, user is root, password is alpine)
- the first ssh will take minutes because SSH keys are generated
- once you are ssh'ed into your phone, run chmod 777 /var/mobile/Documents/mautrix-imessage-armv7
- scan QR Code again
- check that the config file downloaded by running the following over SSH on your iPhone:
cat /var/mobile/Documents/mautrix-imessage-armv7/config.yaml
- If you are seeing
[ERROR] Error in appservice websocket: failed to open websocket: dial tcp [::1]:29331: connect: connection refused
that means that your phone cannot talk tomautrix-wsproxy
, make sure that the configured value for homeserver -> websocket_proxy can be resolved from your phone. You can check this by installingnetcat
in Cydia and then running the following over ssh:nc -zv <hostname> 29331
to see if it connects
SMS forwarding on iOS
If you're running the bridge on an old jailbroken iPhone, but want to keep your SIM card in your main iPhone, you can use iMessage's SMS forwarding feature to still send and receive text messages through the bridge.
By default, outgoing SMSes will only be forwarded on non-iPhone devices, and it'll just throw a no sim card installed error if you try to send an SMS. However, Brooklyn includes a bypass that can make the iPhone act like iPads and Macs and forward the SMS through another iPhone.
To enable the bypass:
- Deactivate iMessage (Settings -> Messages -> switch off "iMessage").
- Enable the bypass in Settings -> Brooklyn.
- Reset network settings (Settings -> General -> Reset -> Reset Network Settings).
- The iPhone will forget your Wi-Fi settings and reboot.
- Set up your Wi-Fi connection again.
- Reactivate iMessage (same switch as step 1).
iMessage SMS bridge setup (Android)
In addition to being an iMessage bridge, mautrix-imessage can run on Android to bridge SMS messages from your phone. The Android SMS bridge works similar to the jailbroken iOS setup, but instead of Brooklyn, the wrapper app for the bridge is android-sms.
Please note that everything in these docs are meant for server admins who want to self-host the bridge. If you're just looking to use the bridges, check out Beeper, which provides fully managed instances of all of these bridges.
Requirements
- An Android device with Android 5 or higher.
- A Matrix homeserver that supports application services (e.g. Synapse). You need access to register an appservice, which usually involves editing the homeserver config file.
- A websocket proxy to receive appservice transactions. If you want end-to-bridge encryption, the sync proxy component (mentioned in the websocket proxy readme) is also recommended to minimize battery usage.
Installation
Compiling manually
- Install the latest Android SDK and NDK version 21.3.6528147.
- Clone the android-sms repo
- The main branch doesn't currently work as a standalone app, so use the
0.1.89
tag. - Use
--recursive
when cloning orgit submodule init && git submodule update
after cloning to ensure that the mautrix-imessage submodule is present.
- The main branch doesn't currently work as a standalone app, so use the
- Run
./mautrix.sh
to compile mautrix-imessage for Android. - Put your
config.yaml
inapp/src/main/assets/
(create the directory if it doesn't exist). - Run
./gradlew installDebug
to compile the app and install it over ADB.
Precompiled builds
There are currently no precompiled versions available, as the config must be bundled at compile time. Support for setting up with QR code similar to the iOS setup will be added soon(™), and precompiled APKs will be available in the GitLab CI after that.
Configuring and running
- Get the example config and fill it out. You'll at least need to:
- Fill everything in the
homeserver
section. - Set
bridge
->user
to your MXID. - Change
imessage
->platform
toandroid
. - Generate random tokens for the
as_token
andhs_token
fields. - The database and log directory paths must be absolute paths in the
/data/user/0/com.beeper.sms.app
directory.
- Fill everything in the
- Get the example registration and copy the relevant values from the config.
- Set up mautrix-wsproxy (and the sync proxy).
- Add the path to the registration file to your Synapse
homeserver.yaml
underapp_service_config_files
, then restart Synapse. - Build and run the android-sms app with your config.
- Open the app and grant it SMS permissions to start the bridge.
If something is wrong and you need to view the bridge logs, use logcat:
adb logcat --pid=$(adb shell ps | grep com.beeper.sms.app | awk '{ print $2 }')
(note that the pid will change if the app is restarted, so you'll have to re-run the command after restarts)