Skip to main content

Matrix Secure Messaging

Shenzhen, China

Setup

Create a work directory and set the necessary permissions:

mkdir -p /opt/matrix/synapse/data
sudo chown -R 1000:1000 /opt/matrix

Then we need an internal docker network for the services to communicate on:

docker network create matrix

Set up the Reverse Proxy

NGINX Proxy Service

jwilder/nginx-proxy nginx-proxy sets up a container running nginx and docker-gen. docker-gen generates reverse proxy configs for nginx and reloads nginx when containers are started and stopped.

nano /opt/matrix/docker-compose.yml
version: "3"

services:
    proxy:
        image: "jwilder/nginx-proxy"
        container_name: "proxy"
        volumes:
            - "certs:/etc/nginx/certs"
            - "vhost:/etc/nginx/vhost.d"
            - "html:/usr/share/nginx/html"
            - "/run/docker.sock:/tmp/docker.sock:ro"
        networks: ["matrix"]
        restart: "always"
        ports:
            - "80:80"
            - "443:443"

networks:
    matrix:
        external: true

volumes:
    certs:
    vhost:
    html:

Letsencrypt Proxy Companion Service

letsencrypt-nginx-proxy-companion:

nano /opt/matrix/docker-compose.yml
version: "3"

services:
    proxy:

        ...

    letsencrypt:
        image: "jrcs/letsencrypt-nginx-proxy-companion"
        container_name: "letsencrypt"
        volumes:
            - "certs:/etc/nginx/certs"
            - "vhost:/etc/nginx/vhost.d"
            - "html:/usr/share/nginx/html"
            - "/run/docker.sock:/var/run/docker.sock:ro"
        environment:
            NGINX_PROXY_CONTAINER: "proxy"
        networks: ["matrix"]
        restart: "always"
        depends_on: ["proxy"]

        ...

Run the compose file with:

docker-compose up -d
curl localhost
<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx</center>
</body>
</html>

Set up Synapse

Configuration

nano /opt/matrix/synapse/docker-compose.yml
version: "3"

services:
    synapse:
        image: "matrixdotorg/synapse:latest"
        container_name: "synapse"
        volumes:
            - "./data:/data"
        environment:
            # Replace this with your domain
            VIRTUAL_HOST: "sub.domain.com"
            VIRTUAL_PORT: 8008
            # Replace this with your domain
            LETSENCRYPT_HOST: "sub.domain.com"
            # Replace this with your domain
            SYNAPSE_SERVER_NAME: "sub.domain.com"
            SYNAPSE_REPORT_STATS: "yes"
        networks: ["matrix"]


networks:
    matrix:
        external: true

Generate the configuration file:

docker-compose run --rm synapse generate

This will generate the config file inside ./data, named homeserver.yaml. We need to make the following changes:

  • The server_name variable is set to the subdomain of your choice, as set in the environment variable SYNAPSE_SERVER_NAME.
  • TLS is set to false. You are using a reverse proxy, so TLS is handled through your web server. Leave the port be.
  • Make sure enable_registration is set to true, so that you can sign up and use your homeserver.
nano /opt/matrix/synapse/data/homeserver.yaml
## Server ##
server_name: "sub.domain.com"
## TLS-enabled listener: for when matrix traffic is sent directly to synapse. ##
listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true

    resources:
      - names: [client, federation]
        compress: false
## Registration ##
enable_registration: true 

Now that everything is in place, you can start synapse using a command as simple as

docker-compose up -d

Matrix Messenger Synapse

Adding PostgreSQL

By default, synapse uses SQLite for its database. For a more important usecase, I recommend using PostgreSQL instead - if you need it, simply add it to your compose file:

nano /opt/matrix/synapse/docker-compose.yml
version: "3"

services:
    synapse:

        ...

    postgresql:
        image: postgres:latest
        restart: always
        environment:
            POSTGRES_PASSWORD: somepassword
            POSTGRES_USER: synapse
            POSTGRES_DB: synapse
            POSTGRES_INITDB_ARGS: "--encoding='UTF8' --lc-collate='C' --lc-ctype='C'"
        volumes:
            - "postgresdata:/var/lib/postgresql/"
        networks: ["matrix"]

        ...

networks:
    matrix:
        external: true

volumes:
    postgresdata:

Configure Synapse

nano /opt/matrix/synapse/data/homeserver.yaml

Comment out the SQLite block:

## Database ##
database:
  name: sqlite3
  args:
    database: /data/homeserver.db

And replace it with:

## Database ##
database:
    name: psycopg2
    args:
        user: synapse
        password: somepassword
        host: postgresql
        database: synapse
        cp_min: 5
        cp_max: 10

The name of the database is psycopg2, which is a PostgreSQL adapter for python. Now reload the compose file:

docker-compose down
docker-compose up -d

Test the Synapse Matrix Homeserver

Our Synapse Server now allows us to use the Matrix protocol to exchange messages. But we still need to install a client to interact with our server. A list of optional clients can be found here.

Matrix Messenger Synapse

Add your server address instead of the official server network and create an account - done!

Setting up Federation in Synapse

Federation is basically the ability to communicate with users on a different homeserver.

By default, each matrix server tries to reach another matrix server via port 8443. The following process basically tells the other servers to use a different port. Because https is already working in port 443, you're simply going to delegate the default matrix communication port to 443.

Configuration File for NGINX

nano /opt/matrix/synapse-federation
location /.well-known/matrix/server {
    return 200 '{"m.server": "sub.domain.com:443"}';
}

Change sub.domain.com to your domain.

Edit the Docker Compose File

Open your docker-compose.yml file and add another entry to the volumes array:

nano /opt/matrix/docker-compose.yml
- ./synapse-federation:/etc/nginx/vhost.d/sub.domain.com

Change sub.domain.com to your domain. Now reload the compose file:

docker-compose down
docker-compose up -d

Testing

Run the curl command and you should receive a true as response (make sure you have jq installed):

curl https://federationtester.matrix.org/api/report?server_name=sub.domain.com --silent | jq -r '.FederationOK'
true

Change sub.domain.com to your domain.

Deactivate Registrations

Once everyone joined shut of the registration option to your server:

nano /opt/matrix/synapse/data/homeserver.yaml
## Registration ##
enable_registration: false

And cycle the synapse service to take effect!