Matrix - Synapse
Matrix is a project to create a decentralized chat / messaging world. Probably much more than that, but i think it's the definitive and only future-proof messaging solution.
It looks amazing and it already has so many features that can replace other proprietary solutions. Unfortunately, it is still quite difficult not only to setup, but also to use. One of the big selling point, in my opinion, are the bridges to the other messaging solutions, but the lack of a really viable whatsapp bridge is a bummer. The reason is due to whatsapp limitation, but i am not ready to give up my main whatsapp account on my phone to move it to a VM running on my server.
The Telegram integration works pretty well, even if the initial setup proved to be a bit shaky, it's solid after that phase. I didnt explore any other bridge at the moment.
Overall i am not yet sure if the effort is worthwile, but since i believe in the need for an open internet, i will give Matrix more time.
Tools and Architecture
Matrix is the high-level protocol. To join, or host, a Matrix network you need a Matrix server implementation. There are quite a few but i choose Synapse because it's solid and well-proven.
In addition to the server itself, you need the bridges if you want to connect your matrix instance to other messaging platforms. I only use Telegram and Whatsapp (well, discord maybe, but it's more of a forum for me than an actual messaging tool), and of these only Telegram has a viable bridge.
More info about the bridges can be found here.
To use Matrix properly you do need one dedicated subdomain. It is teorically possible to host on sub-paths, but i do not recomend it as it adds another layer of uncertainity and complexity that you don't want. I will assume you have https://chat.mydomain.com for your Matrix service. Also note that https is mandatory.
Installation
It is possible to install Synapse and the Telegram bridge on bare-metal leveraging Python Virtual Envs, but unless you want to use a SQLite (which won't scale easily) database, you will also need a PostgresSQL installation.
Overall, i prefer to go the container route which proved to be easy enough. Setting up and running properly your Matrix instance is already tricky that adding a bare-metal installation hurdle didnt seems needed.
As usual create one dedicated user, and create a data folder where all the data will be stored:
useradd -d /data/daemons/synapse -m synapse mkdir /data/synapse mkdir /data/synapse/data mkdir /data/synapse/database mkdir /data/synapse/bridges mkdir /data/synapse/bridges/telegram chown synapse:synapse -R /data/synapse
The data folder will contain Synapse configuration and uploaded files. The database folder will contain the PostgreSQL database. The bridges folders will contain each one bridge various files.
Now, take the following docker-compose.yml file and adapt to your needs:
- docker-composer.yml
version: '3.7' services: synapse: image: docker.io/matrixdotorg/synapse:latest restart: unless-stopped environment: - SYNAPSE_CONFIG_PATH=/data/homeserver.yaml volumes: - /data/synapse/data:/data depends_on: - db ports: - 8008:8008/tcp networks: - synapse-net mautrix-telegram: container_name: mautrix-telegram image: dock.mau.dev/mautrix/telegram:latest restart: unless-stopped depends_on: - db volumes: - /data/synapse/bridges/telegram:/data networks: - synapse-net db: image: docker.io/postgres:12-alpine # Change that password, of course! environment: - POSTGRES_USER=synapse - POSTGRES_PASSWORD=<<< my db password >>> - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C volumes: - /data/synapse/database:/var/lib/postgresql/data networks: - synapse-net networks: synapse-net: {}
Now, as usual, pull the images:
podman compose pull
Generate initial configuration file:
podman compose run --rm -e SYNAPSE_SERVER_NAME=chat.mydomain.com -e SYNAPSE_REPORT_STATS=yes synapse generate
Edit your /data/synapse/data/homeserver.yaml so that you use PostgresSQL, and double check the paths and server name:
- homeserver.yaml
server_name: "chat.mydomain.com" pid_file: /data/homeserver.pid # NOTE: enable the following two lines ONLY to create users, then REMOVE them! #enable_registration: true #enable_registration_without_verification: true listeners: - port: 8008 tls: false type: http x_forwarded: true resources: - names: [client, federation] compress: false database: name: psycopg2 args: user: synapse password: <<< my db password >>> dbname: synapse host: db cp_min: 5 cp_max: 10 log_config: "/data/chat.mydomain.com.log.config" media_store_path: /data/media_store registration_shared_secret: "<<< random secret >>>" report_stats: true macaroon_secret_key: "<<< random key >>>" form_secret: "<<< random secret >>>" signing_key_path: "/data/chat.mydomain.com.signing.key" trusted_key_servers: - server_name: "matrix.org"
At this point, you are ready to run the Matrix.
Set up Telegram Bridge
The main docker-compose.yml above already contains the bridge image, so just run it once to have it create all the files under */data/synapse/bridges/telegram, and then edit the main file: …
Edit the file /data/synapse/bridges/telegram/config.yaml and will in all the required details.
Go to https://my.telegram.org/apps| and generate both an api_id and api_hash. Optionally you can go to the BotFather in Telegram and create a specific bot for you (here)
Some hints on config.yaml:
- homeserver - address: the URL of your instance (https://chat.mydomain.com)
- homeserver - domain: the URL of your instance, cleaned (chat.mydomain.com, yes, this is not a typo)
- appservice - address: the container name of the bridge (so, http://mautrix-telegram:29317)
- appservice - database: i had to switch to SQLite, as i couldn't create a PostgresSQL new database (so, database: sqlite:/data/mautrix-telegram.db)
- permissions: change to match your admin user and instance name (ex: chat.mydomain.com: full \n '@admin:chat.mydomain.com': admin)
- telegram - api_id the API_ID generated on telegram
- telegram - api_hash: API_HASH generated on telegram
- telegram - bot_token: the bot token created on telegram (optional)
Copy the /data/synapse/bridges/telegram/registration.yaml to /data/synapse/data/mautrix-telegram-registration.yaml. If the file is missing, restart the containers to have it generated. If you change anything inside the config.yaml, delete the registration.yaml and restart the containers.
It is very important to note that the registration.yaml file must be correct and copied to the synapse data folder. This is mandatory to let the TelegramBot authenticate in Synapse, and if the bridge does not work, you need to double check that the contents of this file looks correct and match you actual configuration.
Reverse Proxy
You need to run your Matrix behind a reverse proxy so that you can easily add SSL and protect your server. See The Reverse Proxy concept for more details.
This is a simple and effective chat.conf for NGINX:
- chat.conf
server { server_name chat.mydomain.com; listen 8443 ssl; listen 443 ssl; access_log /var/log/nginx/chat.mydomain.com_access_log main; error_log /var/log/nginx/chat.mydomain.com_error_log info; location ~ ^(/_matrix|/_synapse/client) { # note: do not add a path (even a single /) after the port in `proxy_pass`, # otherwise nginx will canonicalise the URI and cause signature verification # errors. proxy_pass http://127.0.0.1:8008; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $host; # Nginx by default only allows file uploads up to 1M in size # Increase client_max_body_size to match max_upload_size defined in homeserver.yaml client_max_body_size 500M; # Synapse responses may be chunked, which is an HTTP/1.1 feature. proxy_http_version 1.1; } include com.mydomain/certbot.conf; }
Autostart & Running
If you are following my Custom User Services approach, it's pretty easy:
cd /etc/local.d ln -s _servicer.sh 63-synapse--podman.start ln -s _servicer.sh 63-synapse--podman.stop
User Creation
One of the not so intuitive things about Matrix is user creation. I didnt waste too much time on this because i only needed two users (and in general, only a limited numnber of family members), so i went the manual way.
After starting the containers, as user synapse, run:
podman compose run --rm --entrypoint /bin/bash synapse /usr/local/bin/register_new_matrix_user https://chat.mydomain.com -c /data/homeserver.yaml