Install Matrix-Synapse including Whatsapp bridge using docker-compose

This howto explains how to install the matrix-synapse server including the mautrix-whatsapp bridge. Maybe other bridges will follow. Thanks to @robb for inspiring and testing.

I ended up using docker-compose because it was the only way for me to make the database container work.

Download and install docker-compose:

curl -L$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

Create the synapse-docker directory:

mkdir /opt/synapse-docker

Create /opt/synapse-docker/docker-compose.yml with following content:

version: '3.7'


    restart: unless-stopped
      - ./synapse-data:/data
      - db
      - ''
    restart: unless-stopped
      - POSTGRES_USER=synapse
      - POSTGRES_PASSWORD=synapse
      - POSTGRES_INITDB_ARGS=--encoding='UTF8' --lc-collate='C' --lc-ctype='C'
      - ./postgres-data:/var/lib/postgresql/data

    container_name: mautrix-whatsapp
    restart: unless-stopped
    - ./mautrix-whatsapp:/data

    name: aqua
    external: true

Create /etc/httpd/conf.d/a_synapse.conf with following content and edit the ServerName to match your domain:

<VirtualHost *:443>
        SSLEngine on
        AllowEncodedSlashes NoDecode
        ProxyPass /_matrix nocanon
        ProxyPassReverse /_matrix

Listen 8448

<VirtualHost *:8448>
        SSLEngine on
        AllowEncodedSlashes NoDecode
        ProxyPass /_matrix nocanon
        ProxyPassReverse /_matrix

Restart httpd to apply the config:

systemctl restart httpd

Enter the synapse-docker dir, else docker-compose won’t work:

cd /opt/synapse-docker

Run the below Docker command to generate the synapse config file, edit SYNAPSE_SERVER_NAME to match your domain:

docker run -it --rm \
    -v $PWD/synapse-data:/data \
    -e \
    matrixdotorg/synapse:latest generate

Remove/comment out the sqlite database and add the postgresql database section in synapse-data/homeserver.yaml so it looks like

#  name: sqlite3
#  args:
#    database: /data/homeserver.db
  name: psycopg2
    user: synapse
    password: synapse
    database: synapse
    host: db # The service name defined in your docker-compose file
    cp_min: 5
    cp_max: 10

Run the following Docker command to generate mautrix-whatsapp config in mautrix-whatsapp:

docker run --rm -v $PWD/mautrix-whatsapp:/data:z

Edit mautrix-whatsapp/config.yaml and change addresses, domain and uri:

  • homeserver address:
  • homeserver domain:
  • appservice address: http://mautrix-whatsapp:29318
  • database uri: postgres://synapse:synapse@db/mautrix?sslmode=disable
  • Set your domain at the permissions section:
        "*": relay
        "": user
        "": admin

Run the following Docker command to generate registration file

docker run --rm -v $PWD/mautrix-whatsapp:/data:z

Copy the registration to a directory where synapse can read it and set owner:

cp mautrix-whatsapp/registration.yaml synapse-data/
chown 991:991 synapse-data/registration.yaml

Add the following registration entry at the end of synapse-data/homeserver.yaml

- /data/registration.yaml

Add the firewall rule for port 8448 (used for federation):

config set synapse service status enabled TCPPort 8448 access red,green
signal-event firewall-adjust

Start the containers using docker-compose:

docker-compose up -d

Wait until containers are up or the following command won’t work because it needs the database container.

To stop the containers if needed, eg for restarting:

docker-compose down

Create mautrix database:

docker exec -it synapse-docker-db-1 psql -U synapse
 OWNER synapse;

Install Element web client v1.11.20, check Releases · vector-im/element-web · GitHub for new releases:

tar -xzf element-v1.11.20.tar.gz
mv element-v1.11.20 /var/www/html/element
cp /var/www/html/element/config.sample.json /var/www/html/element/config.json
rm -f element-v1.11.20.tar.gz

Run the following Docker command to create a user:

docker exec -it synapse-docker-synapse-1 register_new_matrix_user http://localhost:8008 -c /data/homeserver.yaml

Login to the element web client at

To connect to the Whatsapp bridge you need to start a chat to

help shows some information about usable commands.

login shows a QR Code to connect WhatsApp Web to the bridge. After connecting the bridge should work and you get the WA messages in your element client.


To make the synapse admin api work, we need to add a location directive to /etc/httpd/conf.d/a_synapse.conf:

<VirtualHost *:443>
        SSLEngine on
        AllowEncodedSlashes NoDecode
        ProxyPreserveHost on
        ProxyPass /_matrix nocanon
        ProxyPassReverse /_matrix

        <Location /_synapse/admin>
          Require all denied
          # Change the network as needed, we don't want to allow the synapse admin api to public.
          Require ip
          ProxyPass nocanon


The synapse-admin service needs to be added to the docker-compose.yml: (in this example it’s added after the synapse service)


    restart: unless-stopped
      - ./synapse-data:/data
      - ./$
      - db
      - ''

    container_name: synapse-admin
    hostname: synapse-admin
    image: awesometechnologies/synapse-admin
      - "8095:80"
    restart: unless-stopped

A reverse proxy is needed to reach the site:

Start the synapse admin:

docker-compose up -d synapse-admin

Now the Synapse Admin should be reachable via the reverse proxy. Login is possible with synapse admins only.


And another gem is born. Thanks for that @mrmarkuz !


from what file pls?

Is there perhaps an extra step in between ‘Generate…’ SYNAPSE_SERVER_NAME config file and ‘Remove/comment out…’?

Is 'Generate creating text file with nano or executing a command?

ps I replace in my test SYNAPSE_SERVER_NAME with ‘’, so lower case. Is that ok?

Thanks again

Thanks for testing. I’d like to add more bridges so I’m going to reorganize this howto to make the installation easier.

From synapse-data/homeserver.yaml

OK, that’s really confusing. I’m going to edit my post to make it more clear.

The synapse config file synapse-data/homeserver.yaml is created by starting the synapse container once by running docker run ....

There’s no extra step, after creating the file you can edit it.

Sorry, I meant to replace with your domain so it should look like

docker run -it --rm \
    -v $PWD/synapse-data:/data \
    -e \
    matrixdotorg/synapse:latest generate

Should this not be ‘synapse-docker_db_1’



I vaguely recall something was discussed about docker versions using different syntaxes…

Just a note. Anyway, element is up and running and so are the containers. But I can only register with the Matrix server and not on MY server/domain. New things to explore for me :slight_smile:

registration.yaml is copied to synapse-data directory, but the original registration.yaml get’s 991 ownership? Odd or me not understanding?


You are right, it should be

chown 991:991 synapse-data/registration.yaml

I corrected it.

1 Like

I guess this should be ‘- /synapse-data/registration.yaml’ ?

/me hiding… :pleading_face:

No, it’s the path in the container.

From the docker-compose.yml - the local dir synapse-data points to the data dir in the container:

1 Like

Maybe someone has a clue (@robb perhaps?) I followe d this how-to to the letter, but I am unable to create an account when accessing element and changing the homeserver to my domain ( It would display the below error message. Any clue what I am missing or do I expect something that is not possible? Thanks!

Hi @LayLow

If I remember well:

The file config.json should contain your server name as:

    "default_server_config": {
        "m.homeserver": {
            "base_url": "",
            "server_name": ""
        "m.identity_server": {
            "base_url": ""

The file ...well-known/matrix/server should contain;

{ “m.server”: “” }

The port 443 may not be required.

At: , enter your domain for a test: => Go.


homeserver.yaml must contain:

enable_registration: true



Mercie Bien Michel-André,

Ok, where would this file be (path) please?

This file would be at the default apache path of NS I guess?

That shows me that I have very poor skills :wink:

Thanks for the links and assist. I’ll report back!

Please also check the container logs for errors by using portainer or command line.

Show logs of db container for example:

docker logs synapse-docker-db-1

Show all synapse logs using docker-compose:

docker-compose logs


Hi @LayLow

The config.json in under the “client” element and you copy it from config.sample.json in the same directory or just rename it to config.json.

The file .well-known/matrix/server is in the default web directory: /var/www/html/.well-known/matrix/server.

When login in and the server name is not right you have to use https: i.e.

Don’t forget to clear the browser cache…

You can have a look at my document (translated in English by a web page which I don’t remember). The translation is not bad, I didn’t do any correction:


1 Like

Please see synapse_1 | Starting synapse with args -m --con -

There is an error somewhere. I also learned that a yaml file CAN NOT contain any tabs, but idents have to be made by spaces.

See anything?

Hi @michelandre ,

Thanks so much for the details. Let me digest!


There seem to be errors in your homeserver.yaml, check lines 12 and 29:

yaml.parser.ParserError: while parsing a block mapping
in "/data/homeserver.yaml", line 12, column 1
expected <block end>, but found '<block mapping start>'
in "/data/homeserver.yaml", line 29, column 3

You may also share your homeserver.yaml.

Please see DM. I will share the outcome here

Nope, no tabs, and indentation is critical. An indent of two spaces means something completely different than an indent of four spaces.



  1. I had a typo. I used ‘arg’ instead of ‘args’
  2. I had to add suppress_key_server_warning: true (homeserver.yaml)
  3. had to add enable_registration_without_verification: true
  4. Got rid of 4 lines with tabs and replace the with space to the correct position

Obviously verification should be required to prevent spam and bots etc. ut for this testing purpose is allowed me to finally register.

The command ‘docker-compose logs’ is very informative.

Thanks for this time around y’all.

1 Like