Prerequisites
See Part 1 to get a running Synapse server based off a Docker-Compose file, example file included at the bottom of this post. Not necessary, but you can also check out Part 2 for a very similar post but regarding a Signal bridge instead of WhatsApp.
Matrix-WhatsApp Bridge
From a Matrix perspective, this is very similar to the Signal integration. The significant difference is that instead of deploying a daemon that receives the messages directly, this uses the WhatsApp web client. We’ll use the same initial configuration and registration setup, and we’ll also use a Postgres database to store the bridge state.
At this point, the Synapse server is running and stable, so we just have to tackle the bridge itself. Most of this content is based off what is available here: https://docs.mau.fi/bridges/go/whatsapp/index.html
- Update the
docker-compose.yaml
to contain an actual password for the whatsapp-bridge-db. If nothing else, this is a useful step to make sure you’re not mixing up which bridge is using which database - Use an ephemeral Docker container to create the bridge’s configuration file, with the volume we’ll ultimately use in the Docker-Compose version:
$ docker run -it --rm -v whatsapp-bridge-data:/data dock.mau.dev/tulir/mautrix-whatsapp:latest
Didn't find a config file.
Copied default config file to /data/config.yaml
Modify that config file to your liking.
Start the container again after that to generate the registration file.
- Same as for Signal and Syanpse, we’ll update this configuration file:
sudo nano $(docker inspect --format='{{.Mountpoint}}' whatsapp-bridge-data)/config.yaml
- Update a handful of things in this file:
- under
homeserver
:- update
address
to be http://synapse:8008 - update
domain
to be the domain you are ultimately going to use, for me it’snuc.localdomain
- update
- under
appservice
:- update
address
to http://whatsapp-bridge:29328 - under
database
update the type to bepostgres
and theuri
to be the full connection string. For me that looks like:postgres://mautrix_whatsapp:ralGudPassword@whatsapp-bridge-db/whatsapp_bridge_db?sslmode=disable
- Note: ensure you use
?sslmode=disable
at the end of your connection string
- Note: ensure you use
- update
- under
bridge
- under
permission
add yourself as an administrator (e.g."toby@nuc.localdomain": "admin"
)
- under
- under
- Ensure you save the file!
- use another ephemeral Docker container to consume the bridge’s configuration and create a registration file that can be used with Synapse
$ docker run -it --rm -v whatsapp-bridge-data:/data dock.mau.dev/tulir/mautrix-whatsapp:latest
Registration generated. Add the path to the registration to your Synapse config, restart it, then start the bridge.
Didn't find a registration file.
Generated one for you.
Copy that over to synapses app service directory.
- Now we need to get the
registration.yaml
for this bridge into Syanpse. Luckily, it’s in a volume that is mounted to both containers, so it’s straightforward. Edit the Syanpse server’shomeserver.yaml
sudo nano $(docker inspect --format='{{.Mountpoint}}' synapse-data)/homeserver.yaml
- find
app_service_config_files
(if its your first bridge then it’s likely commented out, if so uncomment it) - add the path to the the generated
config.yaml
# A list of application service config files to use
app_service_config_files:
- /whatsapp-bridge/registration.yaml
- Now you should be able to start the WhatsApp bridge and restart Synapse. Note that you might see a couple innocuous errors at the start as both are trying to start simultaneously and connect with one another.
- With the WhatsApp bridge running, it’s time to actually set up your WhatsApp account. This section is deployment agnostic, so you can follow the documentation here.
- Invite (or send a direct message, depending on your client) the WhatsApp bot. The bot will be named as you configured, with a default name of
@whatsappbot
, making mine for example:@whatsappbot:nuc.localdomain
. You’ll get early feedback that it’ll work when you see the icon change to be WhatsApp’s.
- Invite (or send a direct message, depending on your client) the WhatsApp bot. The bot will be named as you configured, with a default name of
- send the message
login
to the bridge bot. Then in WhatsApp on your phone go to the Menu and select WhatsApp Web. - Scan the QR code the bot has sent you to link the device.

Now when you receive a WhatsApp message it should show up in the web client and be pushed to Matrix!
Example docker-compose.yaml
version: "3.7"
volumes:
# We need to do some initial set up outside of Docker-Compose, so make these volumes external
synapse-data:
external: true
whatsapp-bridge-data:
external: true
signal-bridge-data:
external: true
# The Signal daemon (Signald) and the Signal bridge (Mautrix-Signal) need to share a volume
signald-data:
# Use these named volumes just for convenience
signal-bridge-db:
synapse-db:
whatsapp-bridge-db:
services:
synapse-db:
container_name: synapse-db
image: postgres:13-alpine
restart: unless-stopped
environment:
POSTGRES_USER: synapse
POSTGRES_PASSWORD: <GENERATE A PASSWORD HERE> # Make sure to update this!
POSTGRES_DB: synapse_db
# ensure the database gets created correctly
# https://github.com/matrix-org/synapse/blob/master/docs/postgres.md#set-up-database
POSTGRES_INITDB_ARGS: --encoding=UTF-8 --lc-collate=C --lc-ctype=C
volumes:
- synapse-db:/var/lib/postgresql/data
ports:
- 5435:5432/tcp
synapse:
container_name: synapse
image: docker.io/matrixdotorg/synapse:latest
# Since synapse does not retry to connect to the database, restart upon failure
restart: unless-stopped
environment:
- SYNAPSE_CONFIG_PATH=/data/homeserver.yaml
volumes:
- synapse-data:/data
- signal-bridge-data:/signal-bridge
- whatsapp-bridge-data:/whatsapp-bridge
depends_on:
- synapse-db
ports:
- 8008:8008/tcp
- 8448:8448/tcp
whatsapp-bridge-db:
container_name: whatsapp-bridge-db
image: postgres:13-alpine
restart: unless-stopped
environment:
POSTGRES_USER: mautrix_whatsapp
POSTGRES_DB: whatsapp_bridge_db
POSTGRES_PASSWORD: <GENERATE A PASSWORD HERE> # Make sure to update this!
volumes:
- whatsapp-bridge-db:/var/lib/postgresql/data
ports:
- 5436:5432/tcp
whatsapp-bridge:
container_name: whatsapp-bridge
image: dock.mau.dev/tulir/mautrix-whatsapp:latest
restart: unless-stopped
volumes:
- whatsapp-bridge-data:/data
ports:
- 29318:29318/tcp
depends_on:
- whatsapp-bridge-db
# Signal and bridge
signald:
container_name: signald
image: finn/signald:latest
restart: unless-stopped
volumes:
- signald-data:/signald
signal-bridge-db:
container_name: signal-bridge-db
image: postgres:13-alpine
restart: unless-stopped
environment:
POSTGRES_USER: mautrix_signal
POSTGRES_DB: signal_bridge_db
POSTGRES_PASSWORD: <GENERATE A PASSWORD HERE> # Make sure to update this!
volumes:
- signal-bridge-db:/var/lib/postgresql/data
ports:
- 5434:5432/tcp
signal-bridge:
container_name: signal-bridge
image: dock.mau.dev/tulir/mautrix-signal
restart: unless-stopped
volumes:
- signal-bridge-data:/data
- signald-data:/signald
ports:
- 29328:29328/tcp
depends_on:
- signal-bridge-db
- signald