Creazione directory e ingresso
$ sudo mkdir /opt/csirt.regione.toscana.it/vector
$ cd /opt/csirt.regione.toscana.it/vector
Creazione di una password per i DB
$ openssl rand -hex 20
7907640782ec73516069d574a158b56757ee8404
Creazione della rete:
$ docker network create csirt
Contenuto del file docker-compose.yaml
name: matrix-csirt
services:
synapse:
image: "ghcr.io/element-hq/synapse:develop"
networks:
- default
- csirt
restart: always
container_name: "matrix-csirt"
volumes:
- "./data:/data"
environment:
VIRTUAL_HOST: "csirt.regione.toscana.it"
VIRTUAL_PORT: 8008
SYNAPSE_SERVER_NAME: "csirt.regione.toscana.it"
SYNAPSE_REPORT_STATS: "yes"
ports:
- "8008:8008/tcp"
- "8448:8448/tcp"
depends_on:
- postgresql
postgresql:
image: postgres:15.5-bullseye
restart: always
networks:
- default
environment:
POSTGRES_PASSWORD: 7907640782ec73516069d574a158b56757ee8404
POSTGRES_USER: synapse
POSTGRES_DB: synapse
POSTGRES_INITDB_ARGS: "--encoding='UTF8' --lc-collate='C' --lc-ctype='C'"
volumes:
- "./data/postgresdata:/var/lib/postgresql/data"
redis:
restart: always
image: redis:7-alpine
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
volumes:
- ./redis:/data
networks:
default:
csirt:
external: true
Creazione dell'ambiente iniziale:
docker run -it --rm -v ./data:/data -e SYNAPSE_SERVER_NAME=csirt.regione.toscana.it -e SYNAPSE_REPORT_STATS=yes ghcr.io/element-hq/synapse:develop generate
Modifica del file data/homeserver.yaml
per supportare postgres ed eliminare SQLite:
server_name: "csirt.regione.toscana.it"
public_baseurl: "https://matrix.csirt.regione.toscana.it"
pid_file: /data/homeserver.pid
listeners:
- port: 8008
tls: false
type: http
x_forwarded: true
resources:
- names: [client, federation]
compress: false
redis:
enabled: true
host: redis
database:
name: psycopg2
args:
user: synapse
password: 7907640782ec73516069d574a158b56757ee8404
host: postgresql
database: synapse
cp_min: 5
cp_max: 10
log_config: "/data/csirt.regione.toscana.it.log.config"
media_store_path: /data/media_store
registration_shared_secret: "jP7e*OUno*lt3DgKH1drLEZk&kwhtAOAWnSCL6~xaG*+w=Mf,t"
report_stats: true
macaroon_secret_key: "odv7NVlpXJK,iMieCHyrHv6X&ciAG5d1AGCQ;qjzDR9Vh7ftpV"
form_secret: "^gGqv;vuhFKQvF-H^&G;3HBb1QH#rUtb_+psY^Kk;LYxQYd&uZ"
signing_key_path: "/data/csirt.regione.toscana.it.signing.key"
trusted_key_servers:
- server_name: "matrix.org"
Inizialmente vogliamo permettere la registrazione senza verifiche, dato che vogliamo creare l'utente amministratore. Aggiungiamo quindi le righe
enable_registration: true
enable_registration_without_verification: true
al precedente file (non ha importanza dove, basta seguire lo schema yaml).
Creiamo l'utente amministratore (password nuovamente ottenuta con openssl rand -hex 16
):
$ docker compose up -d
$ docker compose exec synapse register_new_matrix_user --config data/homeserver.yaml --user admin --password f57f4ad2a5f1f526141fbad0f9e91fe5 --admin
A questo punto dovremmo avere 3 container attivi:
$ docker compose ps -a
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
matrix-csirt ghcr.io/element-hq/synapse:develop "/start.py" synapse 4 minutes ago Up 4 minutes (healthy) 0.0.0.0:8008->8008/tcp, :::8008->8008/tcp, 0.0.0.0:8448->8448/tcp, :::8448->8448/tcp, 8009/tcp
matrix-csirt-postgresql-1 postgres:15.5-bullseye "docker-entrypoint.s…" postgresql 4 minutes ago Up 4 minutes 5432/tcp
matrix-csirt-redis-1
Iniziamo quindi con la creazione del reverse proxy con nginx: /etc/nginx/sites-available/matrix.csirt.regione.toscana.it.conf
server {
listen 80;
server_name matrix.cisrt.regione.toscana.it;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
listen 8448 ssl http2 default_server;
listen [::]:8448 ssl http2 default_server;
server_name matrix.csirt.regione.toscana.it;
ssl_certificate /etc/letsencrypt/live/matrix.csirt.regione.toscana.it/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/matrix.csirt.regione.toscana.it/privkey.pem;
ssl_session_timeout 1d;
access_log /var/log/nginx/matrix.csirt.regione.toscana.it.access.log;
error_log /var/log/nginx/matrix.csirt.regione.toscana.it.error.log;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_early_data on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:50m;
add_header Strict-Transport-Security max-age=15768000;
ssl_stapling on;
ssl_stapling_verify on;
location ~ ^(/_matrix|/_synapse/client) {
proxy_pass http://localhost:8008;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
client_max_body_size 50M;
proxy_http_version 1.1;
}
}
Prima di abilitare il servizio richiediamo un certificato a letsencrypt:
$ sudo certbot certonly --preferred-challenges http -d matrix.csrit.regione.toscana.it -v
A questo punto possiamo abilitare il sito dopo aver controllato che non ci siano errori di sintassi o simili:
$ sudo ln -sf /etc/nginx/sites-available/matrix.csirt.regione.toscana.it.conf /etc/nginx/sites-enabled
$ sudo nginx -t
$ sudo systemctl restart nginx
Come si vede dal file di configurazione, nginx è in ascolto su due porte: 443
e 8448
. La prima è utilizzata per le connessioni, la seconda per le federazioni tra server. La cosa è abbastanza orribile, di conseguenza vogliamo che tutto avvenga tramite la 443
. Inoltre il nostro mxid
ovvero l'identificativo che viene dopo il nome deve essere csirt.regione.toscana.it
e non matrix.csirt.regione.toscana.it
. Devono essere fatti un paio di aggiustamenti sul server nginx che serve il dominio base. In particolare devono essere aggiunte le seguenti direttive sul file host di nginx:
location ^~ /.well-known {
root /var/www/html/matrix;
}
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://csirt.regione.toscana.it"}, "org.matrix.msc3575.proxy": {"url": "https://matrix.csirt.regione.toscana.it"}}';
}
location /.well-known/matrix/server {
access_log off;
add_header Access-Control-Allow-Origin *;
default_type application/json;
return 200 '{"m.server": "matrix.csirt.regione.toscana.it:443"}';
}
Adesso è possibile commentare le righe
listen 8448 ssl http2 default_server;
listen [::]:8448 ssl http2 default_server;
Controlliamo quindi che tutto funzioni con il federation test: https://federationtester.matrix.org/
In questo modo il server è funzionante: le registrazioni sono aperte, possono essere create stanze e la federazione funziona. Tuttavia
The current /sync endpoint scales badly as the number of rooms on an account increases. It scales badly because all rooms are returned to the client, and clients cannot opt-out of a large amount of extraneous data such as receipts. On large accounts with thousands of rooms, the initial sync operation can take minutes to perform. This significantly delays the initial login to Matrix clients, and also makes incremental sync very heavy when resuming after any significant pause in usage.
Dobbiamo abilitare lo sliding-sync. Modifichiamo quindi il file docker-compose.yaml
come segue, aggiungendo questi due servizi (proxy per lo sliding-sync e relativo DB). Anche in questo caso le password del db postgres sono create con openssl rand -hex 20
, mentre il secret openssl rand -hex 32
:
ssync-proxy:
image: ghcr.io/matrix-org/sliding-sync:main
restart: unless-stopped
ports:
- "8888:8888/tcp"
environment:
- "SYNCV3_SECRET=e822aaf8db24b435ad2f8667230669481ad854906cc55b542bf6069f96f0aec2"
- "SYNCV3_SERVER=https://matrix.csirt.regione.toscana.it"
- "SYNCV3_DB=user=syncv3 dbname=syncv3 sslmode=disable host=ssync-db password=24a3c171c4d71ad22dbede055ba32ae53d9ea076"
- "SYNCV3_BINDADDR=0.0.0.0:8888"
depends_on:
- ssync-db
ssync-db:
image: docker.io/postgres:15-alpine
restart: unless-stopped
environment:
- POSTGRES_USER=syncv3
- POSTGRES_PASSWORD=24a3c171c4d71ad22dbede055ba32ae53d9ea076
- POSTGRES_DB=syncv3
volumes:
- "./ssync_db_data:/var/lib/postgresql/data"
E anche il file di configurazione di nginx matrix.csirt.regione.toscana.it
deve essere modificato:
location ~ ^/(client/|_matrix/client/unstable/org.matrix.msc3575/sync) {
proxy_pass http://localhost:8888;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
}
All'interno del file docker-compose.yaml
si aggiunge il servizio element-web
per potersi connettere via browser:
element-web:
image: vectorim/element-web:latest
restart: unless-stopped
volumes:
- ./config.json:/app/config.json
ports:
- 18080:80
e il file config.json
contiene:
{
"default_server_config": {
"m.homeserver": {
"base_url": "https://matrix.csirt.regione.toscana.it",
"server_name": "matrix.csirt.regione.toscana.it"
},
"m.identity_server": {
"base_url": "https://vector.im"
}
},
"disable_custom_urls": false,
"disable_guests": false,
"disable_login_language_selector": false,
"disable_3pid_login": false,
"brand": "Element",
"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"
],
"bug_report_endpoint_url": "https://element.io/bugreports/submit",
"uisi_autorageshake_app": "element-auto-uisi",
"default_country_code": "IT",
"show_labs_settings": false,
"features": {},
"default_federate": true,
"default_theme": "light",
"room_directory": {
"servers": ["matrix.org"]
},
"enable_presence_by_hs_url": {
"https://matrix.org": false,
"https://matrix-client.matrix.org": false
},
"setting_defaults": {
"breadcrumbs": true,
"UIFeature.deactivate": false,
"UIFeature.registration": true,
"UIFeature.passwordReset": false
},
"jitsi": {
"preferred_domain": "meet.element.io"
},
"element_call": {
"url": "https://call.element.io",
"participant_limit": 8,
"brand": "Element Call"
},
"map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
}
Per bilanciare il carico, aggiungiamo due ulteriori servizi:
sync-worker:
image: "ghcr.io/element-hq/synapse:develop"
container_name: sync-worker
restart: unless-stopped
entrypoint: ["/start.py", "run", "--config-path=/data/homeserver.yaml", "--config-path=/data/workers/sync-worker.yaml"]
volumes:
- ./data:/data
environment:
SYNAPSE_WORKER: synapse.app.generic_worker
depends_on:
- postgresql
- synapse
ports:
- "18083:8083/tcp"
sync-worker-client:
image: "ghcr.io/element-hq/synapse:develop"
container_name: sync-worker-client
restart: unless-stopped
entrypoint: ["/start.py", "run", "--config-path=/data/homeserver.yaml", "--config-path=/data/workers/sync-worker-client.yaml"]
volumes:
- ./data:/data
environment:
SYNAPSE_WORKER: synapse.app.generic_worker
depends_on:
- postgresql
- synapse
ports:
- "18082:8082/tcp
Dovremo quindi creare i file /data/workers/sync-worker.yaml
e /data/workers/sync-worker-client.yaml
, oltre a modificare homeserver.yaml
$ sudo mkdir data/workers
Partiamo quindi dal sync-worker-yaml
:
worker_app: synapse.app.generic_worker
worker_name: sync-worker
# The replication listener on the main synapse process.
worker_listeners:
- type: http
port: 8083
x_forwarded: true
resources:
- names:
- client
- federation
- type: http
port: 8084
resources:
- names: [replication]
compress: false
e proseguiamo con sync-worker-client.yaml
worker_app: synapse.app.generic_worker
worker_name: sync-worker-client
# The replication listener on the main synapse process.
worker_listeners:
- type: http
port: 8082
x_forwarded: true
resources:
- names:
- client
- federation
- type: http
port: 8085
resources:
- names: [replication]
compress: false
Mappiamo i nuoi servizi in homeserver.yaml
: