Post

Synapse, Element & Coturn

Présentation

Synapse

Synapse est un serveur domestique Matrix open-source écrit et maintenu par la Fondation Matrix.org. Le développement de Synapse et du protocole Matrix lui-même se poursuit sérieusement aujourd’hui.En bref, Matrix est un standard ouvert pour les communications sur Internet, prenant en charge la fédération, le cryptage et la VoIP. Matrix.org en dit plus sur les objectifs du projet Matrix, et la spécification formelle décrit les détails techniques.

Element

Element (anciennement connu sous le nom de Vector et Riot) est un client web Matrix construit à l’aide du kit SDK React de Matrix.

Coturn

coturn est une implémentation libre et gratuite de TURN et de STUN Server.Le serveur TURN est un serveur et une passerelle de traversée NAT pour le trafic VoIP.

L’association de ces 3 outils vous permet donc d’avoir à disposition un ensemble composant cette messagerie instantanée (un peu comme Discord) supportant les appels audio et vidéo.

Prérequis

Je pars, comme d’habitude, du principe que vous disposez de Docker et de Portainer, que vous souhaitez installer le tout sous Linux et que vous utilisez un reverse proxy pour exposer vos services (Caddy).

Pour simplifier cet article, je considère que vous avez déjà les services suivants qui sont pleinement opérationnels :

  • Redis
  • PostgreSQL

Vous aurez à créer les répertoires ci-dessous (en partant du principe que vous êtes sur /opt/docker/matrix/ comme répertoire de base) :

  • conf/nginx
  • datas/coturn
  • datas/discord (factultatif)
  • datas/synapse (factultatif)
  • datas/telegram (factultatif)
  • datas/whatsapp (factultatif)

Vous aurez besoin des fichiers ci-dessous :

docker-compose.yml

[Fichier]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
version: "3.0"

#
# updated: 2023-04-05
# stack:   matrix
#

#
# If you don's want Telegam, WhatsApp or Discord bridge, you may remove the relevant section(s)
#

# sudo docker run -it --rm \
#     -v /opt/docker/standard/matrix/work:/data \
#     -e SYNAPSE_SERVER_NAME=matrix.domain.com \
#     -e SYNAPSE_REPORT_STATS=yes \
#     matrixdotorg/synapse:latest generate

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

services:
  element:
    container_name: element
    hostname: element
    image: vectorim/element-web:latest
    restart: always
    stdin_open: true
    tty: true
    security_opt:
      - "no-new-privileges:true"
    ports:
      - "7080:80"
    expose:
      - "80"
    depends_on:
      - synapse
    environment:
      TZ: "Europe/Paris"
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/docker/matrix/conf/element-config.json:/app/config.json
  synapse:
    container_name: synapse
    hostname: synapse
    image: matrixdotorg/synapse:latest
    restart: always
    stdin_open: true
    tty: true
    security_opt:
      - "no-new-privileges:true"
    ports:
      - "8008:8008"
    expose:
      - "8008"
    depends_on:
      - synapserp
      - coturn
    environment:
      TZ: "Europe/Paris"
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/docker/matrix/datas/synapse:/data
  synapserp:
    container_name: synapserp
    hostname: synapserp
    image: nginx:latest
    restart: always
    stdin_open: true
    tty: true
    security_opt:
      - "no-new-privileges:true"
    ports:
      - "3080:80"
    expose:
      - "80"
    environment:
      TZ: "Europe/Paris"
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/docker/matrix/conf/nginx:/etc/nginx/conf.d
  coturn:
    container_name: coturn
    hostname: coturn
    image: coturn/coturn:latest
    restart: always
    stdin_open: true
    tty: true
    security_opt:
      - "no-new-privileges:true"
    ports:
      - "3478:3478"
      - "5349:5349"
      - "3478:3478/udp"
      - "5349:5349/udp"
      - "14000-15535:64000-65535/udp"
    expose:
      - "3478"
      - "5349"
      - "64000-65535"
    environment:
      TZ: "Europe/Paris"
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/docker/matrix/conf/turnserver.conf:/etc/coturn/turnserver.conf
      - /opt/docker/matrix/datas/coturn:/var/lib/coturn
  telegram:
    container_name: telegram
    hostname: telegram
    image: dock.mau.dev/mautrix/telegram:latest
    restart: always
    stdin_open: true
    tty: true
    security_opt:
      - "no-new-privileges:true"
    ports:
      - "29317:29317"
    expose:
      - "29317"
    depends_on:
      - synapse
    environment:
      TZ: "Europe/Paris"
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/docker/matrix/datas/telegram:/data
  whatsapp:
    container_name: whatsapp
    hostname: whatsapp
    image: dock.mau.dev/mautrix/whatsapp:latest
    restart: always
    stdin_open: true
    tty: true
    security_opt:
      - "no-new-privileges:true"
    ports:
      - "29318:29318"
    expose:
      - "29318"
    depends_on:
      - synapse
    environment:
      TZ: "Europe/Paris"
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/docker/matrix/datas/whatsapp:/data
  discord:
    container_name: discord
    hostname: discord
    image: dock.mau.dev/mautrix/discord:latest
    restart: always
    stdin_open: true
    tty: true
    security_opt:
      - "no-new-privileges:true"
    ports:
      - "29334:29334"
    expose:
      - "29334"
    depends_on:
      - synapse
    environment:
      TZ: "Europe/Paris"
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /opt/docker/matrix/datas/discord:/data

element-config.json

[Fichier]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
{
	"default_server_config": {
		"m.homeserver": {
			"base_url": "https://matrix.domain.com",
			"server_name": "matrix.domain.com"
		},
		"m.identity_server": {
			"base_url": "https://vector.im"
		}
	},
    "brand": "Matrix",
    "integrations_ui_url": "https://scalar.vector.im/",
    "integrations_rest_url": "https://scalar.vector.im/api",
    "integrations_widgets_urls": [
        "https://scalar.vector.im/_matrix/integrations/v1",
        "https://scalar.vector.im/api",
        "https://scalar-staging.vector.im/_matrix/integrations/v1",
        "https://scalar-staging.vector.im/api",
        "https://scalar-staging.riot.im/scalar/api"
    ],
    "hosting_signup_link": "https://element.io/matrix-services?utm_source=element-web&utm_medium=web",
    "bug_report_endpoint_url": "https://element.io/bugreports/submit",
    "uisi_autorageshake_app": "element-auto-uisi",
    "showLabsSettings": true,
    "roomDirectory": {
        "servers": [
            "matrix.org",
            "gitter.im",
            "libera.chat"
        ]
    },
    "enable_presence_by_hs_url": {
        "https://matrix.org": false,
        "https://matrix-client.matrix.org": false
    },
    "terms_and_conditions_links": [
        {
            "url": "https://element.io/privacy",
            "text": "Privacy Policy"
        },
        {
            "url": "https://element.io/cookie-policy",
            "text": "Cookie Policy"
        }
    ],
    "hostSignup": {
      "brand": "Matrix",
      "cookiePolicyUrl": "https://element.io/cookie-policy",
      "domains": [
          "matrix.org"
      ],
      "privacyPolicyUrl": "https://element.io/privacy",
      "termsOfServiceUrl": "https://element.io/terms-of-service",
      "url": "https://ems.element.io/element-home/in-app-loader"
    },
    "sentry": {
        "dsn": "https://029a0eb289f942508ae0fb17935bd8c5@sentry.matrix.org/6",
        "environment": "develop"
    },
    "posthog": {
        "projectApiKey": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
        "apiHost": "https://posthog.element.io"
    },
    "privacy_policy_url": "https://element.io/cookie-policy",
    "features": {
        "feature_spotlight": true,
        "feature_video_rooms": true
    },
    "element_call": {
        "url": "https://element-call.netlify.app"
    },
    "map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
}

homeserver.yaml

[Fichier]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# Configuration file for Synapse.
#
# This is a YAML file: see [1] for a quick introduction. Note in particular
# that *indentation is important*: all the elements of a list or dictionary
# should have the same indentation.
#
# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
#
# For more information on how to configure Synapse, including a complete accounting of
# each option, go to docs/usage/configuration/config_documentation.md or
# https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html
server_name: "matrix.domain.com"
pid_file: /data/homeserver.pid
federation_rc_reject_limit: 128
listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true
    resources:
      - names: [client, federation]
        compress: false
#database:
#  name: sqlite3
#  args:
#    database: /data/homeserver.db
database:
  name: psycopg2
  args:
    user: [removed]
    password: [removed]
    database: synapse
    host: [removed]
    cp_min: 5
    cp_max: 10
log_config: "/data/matrix.domain.com.log.config"
media_store_path: /data/media_store
registration_shared_secret: "[removed]"
report_stats: true
macaroon_secret_key: "[removed]"
form_secret: "[removed]"
signing_key_path: "/data/matrix.domain.com.signing.key"
trusted_key_servers:
  - server_name: "matrix.org"

enable_registration: true
registrations_require_3pid:
  - email
admin_contact: 'mailto:admin@domain.com'
email:
  smtp_host: [smtp server address]
  smtp_port: [smtp port]
  smtp_user: [username]
  smtp_pass: [password]
  force_tls: true
  require_transport_security: true
  enable_tls: true
  notif_from: "Matrix <admin@domain.com>"
  app_name: "Matrix"
  enable_notifs: true
  notif_for_new_users: false
  validation_token_lifetime: 15m
  invite_client_location: https://element.domain.com
  subjects:
    message_from_person_in_room: "[%(app)s] Vous avez un message sur %(app)s de %(person)s dans le canal %(room)s..."
    message_from_person: "[%(app)s] Vous avez un message sur %(app)s de %(person)s..."
    messages_from_person: "[%(app)s] Vous avez des messages sur %(app)s de %(person)s..."
    messages_in_room: "[%(app)s] Vous avez des messages sur %(app)s dans le canal %(room)s..."
    messages_in_room_and_others: "[%(app)s] Vous avez des messages sur %(app)s dans le canal %(room)s et d'autres..."
    messages_from_person_and_others: "[%(app)s] Vous avez des messages sur %(app)s de %(person)s et d'autres..."
    invite_from_person_to_room: "[%(app)s] %(person)s vous invite à rejoindre le canal %(room)s sur %(app)s..."
    invite_from_person: "[%(app)s] %(person)s vous a invité à chatter sur %(app)s..."
    password_reset: "[%(server_name)s] Réinitialisation du mot de passe"
    email_validation: "[%(server_name)s] Validez votre email"
redis:
  enabled: true
  host: [ip of redis server]
room_list_publication_rules:
  - user_id: "*"
    alias: "*"
    room_id: "*"
    action: allow
turn_uris:
  - "turns:turn.domain.com?transport=udp"
  - "turns:turn.domain.com?transport=tcp"
  - "turn:turn.domain.com?transport=udp"
  - "turn:turn.domain.com?transport=tcp"
turn_shared_secret: "[a secret here !]"
turn_user_lifetime: "1h"
turn_username: [username]
turn_password: [password]
app_service_config_files:
- /data/mautrix-telegram-registration.yaml #only if you keep telegram bridge
- /data/mautrix-whatsapp-registration.yaml #only if you keep whatsapp bridge
- /data/mautrix-discord-registration.yaml #only if you keep discord bridge

# vim:ft=yaml

turnserver.conf

[Fichier]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
syslog

lt-cred-mech
use-auth-secret
static-auth-secret=[password]

realm=matrix.domain.com
server-name=matrix.domain.com

cert=/etc/letsencrypt/live/turn.example.org/fullchain.pem
pkey=/etc/letsencrypt/live/turn.example.org/privkey.pem

#no-udp
external-ip=[public external ip]
min-port=14000
max-port=15535

Pour Coturn, la plage de port (en UDP) qui lui est alloué est 14000-15535.

Il vous faudra penser à les ouvrir, soit sur votre box internet, soit sur votre routeur.

conf/nginx/default.conf

[Fichier]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 2023-04-02

server {
	listen         80 default_server;
	server_name    matrix.domain.com;

	location /_matrix {
		proxy_pass http://192.168.50.102:8008;
		proxy_set_header X-Forwarded-For $remote_addr;
		client_max_body_size 128m;
	}

	location /.well-known/matrix/server {
		access_log off;
		add_header Access-Control-Allow-Origin *;
		default_type application/json;
		return 200 '{"m.server": "matrix.domain.com:443"}';
	}

	location /.well-known/matrix/client {
		access_log off;
		add_header Access-Control-Allow-Origin *;
		default_type application/json;
		return 200 '{"m.homeserver": {"base_url": "https://matrix.domain.com"}}';
	}

	location / {
		return 301 /_matrix/static/;
	}
}

default.conf est pour le cas ou vous utilisiez Traefik et non Caddy

Méthodologie

Tout d’abord, vous placez les fichiers requis dans les répertoires indiqués par le fichier docker-compose.

Dans le fichier element-config.json, il vous faudra mettre à jour le nom de domaine sur lequel vous souhaiter que les services soient associés. Et pour le fichier turnserver.conf, il faudra modifier a minima la partie [password] et si vous le souhaitez la plage des ports alloués. Dans le fichier homeserver.yaml il vous faut aussi mettre à jour le nom de domaine ainsi que toutes les entrées entre crochets.

Les ports des services sont renseignés à plusieurs endroits, si vous devez les modifier pensez à reporter ces changements partout.

Avant de lancer la stack entièrement, il vous faudra lancer la commande suivante afin d’initialiser la configuration de Synapse:

1
2
3
4
5
sudo docker run -it --rm \
    -v /opt/docker/matrix/datas/synapse/:/data \
    -e SYNAPSE_SERVER_NAME=matrix.domain.com \
    -e SYNAPSE_REPORT_STATS=yes \
    matrixdotorg/synapse:latest generate

Pensez à modifier le SYNAPSE_SERVER_NAME

Une fois la stack complète lancée, vous devez lancer un shell sur le conteneur de Synapse pour créer le premier utilisateur (qui sera donc administrateur du serveur) :

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

La partie propre à la configuration de Caddy est relativement simple :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@matrix host matrix.domain.com
handle @matrix {
    import common

    header /.well-known/matrix/* Content-Type application/json
    header /.well-known/matrix/* Access-Control-Allow-Origin *
    respond /.well-known/matrix/server `{"m.server": "matrix.domain.com:443"}`
    respond /.well-known/matrix/client `{"m.homeserver":{"base_url":"https://matrix.domain.com"}}`

    reverse_proxy /_matrix/* [ip]:8008
    reverse_proxy /_synapse/client/* [ip]:8008
}
@element host element.domain.com
handle @element {
    import common

    reverse_proxy [ip]:7080
}

Pour le contenu de common, je vous renvoie à mon autre article Caddy, Docker et Cloudflare.

Si vous utilisez Traefik, vous aurez à ajouter ces élements dans le config.yml :

routers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    synapse:
      entryPoints:
        - https
      rule: Host(`matrix.domain.com`)
      middlewares:
        - default
      tls: {}
      service: synapse

    element:
      entryPoints:
        - https
      rule: Host(`element.domain.com`)
      middlewares:
        - default
      tls: {}
      service: element

services

1
2
3
4
5
6
7
8
9
10
11
     element:
      loadBalancer:
        servers:
          - url: "http://[element's ip addres]:7080"
        passHostHeader: true

    synapse:
      loadBalancer:
        servers:
          - url: "http://[synapse reverse proxy ip addres]:3080"
        passHostHeader: true

Une fois tous ces préparatifs réalisés, vous pourrez lancer la stack avec Portainer.

Les ‘bridges’

Synapse permet de lui connecter différents autres services tels que Telegram, WhatsApp, Discord et bien d’autres.

Je vous renvoie vers les instructions spécifiques à chaque service que vous voulez intégrer à Synapse :

https://docs.mau.fi/bridges/general/docker-setup.html?bridge=telegram&ref=infos.zogg.fr

Dans le cadre de ce tutoriel, l’intégration des services est donnée à titre d’exemple et dépasse le cadre de la mise en place de Synapse et Element :)

Communiquez !

Quelques exemples de l’interface desktop :

Il existe bien entendu des applications iOS et Android officielles :

Conclusion

Vous avez la base technique pour l’installation, à domicile, d’un outil de communication décentralisé, collaboratif et extensible.

Je ne suis pas rentré ici dans le détail de la mise en place du serveur Redis (c’est très simple) ni du serveur de base de données PostgreSQL (c’est presque simple) car ce sera probablement traité dans d’autres articles à venir.

Quant à l’administration et la gestion du serveur, des canaux de communication ; tout cela sort du contexte lié à la simple mise en place du service :)

Extensible ?

Oui, tout à fait puisque vous pouvez y connecter différents autres canaux de communication.

En voici une brève liste :

  • IRC
  • Slack
  • Discord
  • WhatsApp
  • SMS
  • Skype
  • Email
  • Signal
  • Telegram
  • Mastodon

Changelog

2023-04-06

  • Mise à jour de la structure des répertoires
  • Ajout des bridges Telegram, WhatsApp et Discord
Cet article est sous licence CC BY 4.0 par l'auteur.

© 2022- Olivier. Certains droits réservés.

Propulsé par τζ avec le thème Χ