Unify Signal, WhatsApp and SMS in a personal Matrix server: Part 3 (WhatsApp)

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

  1. 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
  2. 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.
  1. Same as for Signal and Syanpse, we’ll update this configuration file:
    1. sudo nano $(docker inspect --format='{{.Mountpoint}}' whatsapp-bridge-data)/config.yaml
    2. 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’s nuc.localdomain
      • under appservice:
        • update address to http://whatsapp-bridge:29328
        • under database update the type to be postgres and the uri 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
      • under bridge
        • under permission add yourself as an administrator (e.g. "toby@nuc.localdomain": "admin")
    3. Ensure you save the file!
  2. 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.
  1. 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’s homeserver.yaml
    1. sudo nano $(docker inspect --format='{{.Mountpoint}}' synapse-data)/homeserver.yaml
    2. find app_service_config_files (if its your first bridge then it’s likely commented out, if so uncomment it)
    3. 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
  1. 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.
  2. 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.
    1. 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 the WhatsApp bridge bot to chat
  1. send the message login to the bridge bot. Then in WhatsApp on your phone go to the Menu and select WhatsApp Web.
  2. Scan the QR code the bot has sent you to link the device.
Link your account

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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s