Self hosted Matrix server

Těžko by jste asi hledali někoho, kdo nikdy neposlal ani jednu zprávu přes Messenger nebo podobnou službu. Asi můžeme říct, že je to jeden z nejrozšířenějších komunikačních prostředků současnosti.

S rostoucím podílem těchto služeb v oblasti všeobecné komunikace vyvstal i takový nešvar. Hovorově bychom mohli říct "fízlování". V reálu to bude nějaká sada algoritmů, která se snaží na základě klíčových slov, frází nebo nějaké sofistikovanější analýzy rozpoznat závadný či protiprávní obsah. Tyto praktiky se většinou zaštiťují ochranou dětí před XYZ a podobné zavádějící důvody. Ale o problematice svobody slova a práva na soukromí tento příspěvek není.

Klasické textové komunikační služby ukládají vaše zprávy v nešifrované podobě. Nemáte vůbec tušení jak dlouho se vaše data uchovávají a za jakým účelem (většinou marketing) mohou být přeprodávána. A už vůbec nevíte, kdy a kdo, to může použít proti vám. (byť třeba vytržené z kontextu)

Situaci si můžete vylepšit tím, že používáte "end-to-end" šifrované komunikátory. Telegram, Signal, Threema a podobně. Při této metodě komunikace by v ideálním případě zprostředkovatel neměl být schopný zprávy jakkoliv dešifrovat.

Tak je to možná v ideálním světě. V tom našem můžeme narazit na pár úskalí. Musíme zprostředkovateli věřit, že dodává takovou službu jakou inzeruje. I když nemusí vidět přímo obsah zpráv, stále si může uchovávat kdo, kdy a s kým komunikoval. Nepříjemností taky je registrace podmíněná poskytnutím telefonního čísla. Telefonní číslo za určitých podmínek dává smysl a používání aplikace je díky němu komfortnější, ale taky je to další vektor útoku na vaši identitu.

Alternativní možností je zprovoznit vlastní Matrix server. Pokud o tom slyšíte poprvé, můžete prozkoumat Fediverse ekosystém a pořádně se ponořit do králičí nory.

Jen ve zkratce popis na wikipedii.

The fediverse (a portmanteau of federation and universe) is an ensemble of federated (i.e. interconnected) servers that are used for web publishing (i.e. social networking, microblogging, blogging, or websites) and file hosting, but which, while independently hosted, can communicate with each other. On different servers (instances), users can create so-called identities. These identities are able to communicate over the boundaries of the instances because the software running on the servers supports one or more communication protocols which follow an open standard.[1] As an identity on the fediverse, users are able to post text and other media, or to follow posts by other identities.[2] In some cases, users can show or share data (video, audio, text, and other files) publicly or to a selected group of identities and allow other identities to edit other users\' data (such as a calendar or an address book). from https://en.wikipedia.org/wiki/Fediverse

Pro naše účely není tento aspekt úplně klíčový.

Co vlastně získáme tím, že zprovozníme vlastní Matrix server?

  • Komunikace používá end-to-end šifrování. Nikdo kromě příjemce by neměl být schopný zprávu vidět.
  • Data leží na našem "železe" a v námi kontrolovaném operačním systému. Sami si můžete překontrolovat jak a jaká data jsou v databázi ukládána.
  • Starou dobrou registraci s uživatelským jménem a heslem. Nejsou potřeba žádné emaily nebo telefonní čísla.
  • Nikdo probíhající komunikaci "nefízluje".
  • Kód je open source. Každý do něho může nahlédnout. Možnost úmyslného zanešení nějakého škodlivého kusu kódu je hodně malá. Komunita by jim to brzy omlátila o hlavu.
  • Máte na výběr z vícero klientů. I když tohle může být někdy i negativum než pozitivum.
  • Moderní klienti moc nezaostávají za předními hráči na trhu. Ano jde poznat, že do toho nebylo nasypáno tolik peněz a „user experience“ není tak „smooth“. To ale nic nemění na tom, že můžete posílat zprávy, fotky, videa, emoji, nálepky, gify nebo provádět video telefonáty. Všechno je technicky funkční.
  • Je možné provozovat komunikaci s jednotlivými lidmi, skupinové komunikace nebo vytvářet místnosti.

Výhod se najde asi ještě více, ale tou nejdůležitější vlastní kontrola.

Nevýhod se najde taky dost. Vůbec samotné rozeběhnutí vyžaduje lehce technický „skill“. Plus věci okolo jako domény, reverzní proxy atd.

Tak a teď teda k tomu co a jak je potřeba rozeběhnout.

Rozeběhnout to můžete skoro na čemkoliv, ale já pro naše účely použil RPi 3B+ s SSD diskem. Pro běh jednotlivých služeb použijeme Docker a Docker-Compose. Jak nainstalovat Docker je popsáno v jiném článku na tomto blogu.

Náš stack obsahje následující Docker obrazy.

  • portainer/portainer-ce:latest
  • matrixdotorg/synapse:latest
  • postgres:14
  • vectorim/element-web:latest

Portainer slouží jen pro pohodlnější správu Docker kontejnerů.

Jako Matrix server použijeme Synapse. Je to implementace Matrix serveru v Pythonu.

Postgres 14 bude naše databáze. V základu používá Synapse Sqlite3, ale pokud máme tu možnost, bude lepší použít Postgres.

Element je webový klient pro Matrix server.

V domovském adresáři si vytvoříme složku matrix-stack a začneme skládat Docker-Compose soubor.

cd ~
mkdir matrix-stack
nano ./matix-stack/docker-compose.yml
version: '3.3'

services:
  portainer:
    container_name: portainer
    image: portainer/portainer-ce:latest
    restart: always
    ports:
      - "9000:9000"
    volumes:
      - portainer_data:/data
      - /var/run/docker.sock:/var/run/docker.sock

  synapse:
    container_name: synapse
    image: matrixdotorg/synapse:latest
    restart: always
    ports:
      - 8008:8008
    volumes:
      - /var/docker_data/matrix:/data

  postgres:
    container_name: postgres
    image: postgres:14
    restart: unless-stopped
    ports:
      - "5432:5432"
    volumes:
     - /var/docker_data/postgresdata:/var/lib/postgresql/data

    environment:
     - POSTGRES_DB=synapse
     - POSTGRES_USER=synapse
     - POSTGRES_PASSWORD=SUPERSECRETLONGPASSWORD
     - POSTGRES_INITDB_ARGS=--lc-collate C --lc-ctype C --encoding UTF8

  element:
    container_name: element
    image: vectorim/element-web:latest
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - /var/docker_data/element-config.json:/app/config.json

volumes:
  portainer_data:

Pro Synapse místo Sqlite3 použijeme Postgre databázi. Víceméně se standardním nastavením kromě jedné věci.

POSTGRES_INITDB_ARGS=--lc-collate C --lc-ctype C --encoding UTF8

Matrix vyžaduje aby LC_COLLATE a LC_TYPE nastaveny na C. Má to co do činění s akceptováním různých znakových sad.

When LC_CTYPE is C or POSIX, any character set is allowed, but for other settings of LC_CTYPE there is only one character set that will work correctly. Since the LC_CTYPE setting is frozen by initdb, the apparent flexibility to use different encodings in different databases of a cluster is more theoretical than real, except when you select C or POSIX locale (thus disabling any real locale awareness).

Před tím, než pustíme docker-compose, je potřeba udělat ještě pár věcí.

Potřebujeme vygenerovat konfigurační soubor pro Synapse server.

docker run -it --rm \
    -v "/var/docker_data/matrix:/data" \
    -e SYNAPSE_SERVER_NAME=matrix.YOUR_DOMAIN.com \
    -e SYNAPSE_REPORT_STATS=no \
    matrixdotorg/synapse:latest generate

A v nově vygenerovaném souboru předělat Sqlite3 na Postgre. Stačí zakomentovat sekci s Sqlite3 a vložit novou.

database:
  name: psycopg2
  args:
    user: synapse
    password: SUPERSECRETLONGPASSWORD
    database: synapse
    host: postgres
    cp_min: 5
    cp_max: 10

Potom je potřeba vytořit konfigurační soubor pro Element.

sudo nano /etc/docker_data/element-config.yaml
{
    "default_server_config": {
        "m.homeserver": {
            "base_url": "https://matrix.YOUR_DOMAIN.com",
            "server_name": "matrix.YOUR_DOMAIN.com"
        },
        "m.identity_server": {
            "base_url": "https://vector.im"
        }
    },
    "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"
    ],
    "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,
    "piwik": {
        "url": "https://piwik.riot.im/",
        "siteId": 1,
        "policyUrl": "https://element.io/cookie-policy"
    },
    "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": "Element Home",
      "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"
    },
    "features": {
        "feature_spotlight": true
    },
    "map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
}

V horní části souboru upravte pro vaši doménu.

"default_server_config": {
        "m.homeserver": {
            "base_url": "https://matrix.YOUR_DOMAIN.com",
            "server_name": "matrix.YOUR_DOMAIN.com"
        },
        "m.identity_server": {
            "base_url": "https://vector.im"
        }
    }

Tak a teď už můžeme pustit ten docker. Přesuneme se do složky s Docker-Compose souborem a spustíme příkaz docker-compose.

cd ~/matrix-stack
docker-compose up -d

Pokud všechno proběhne dle plánu, tak se můžete zkusit přihlásit do Portaineru a měli byste vidět něco takového.

Teď se potřebujeme připojit do docker kontejneru kde beží Synapse odkud budeme přes příkaz register_new_matrix_user přidávat uživatele.

docker exec -it synapse /bin/bash
register_new_matrix_user -c /data/homeserver.yaml http://127.0.0.1:8008

Příkaz vás následně navede co vyplnit.

V tomto bodě nám už vše běží a máme vytvořeného prvního uživatele. Pokud se přes prohlížeč podíváte na http://<ip-adresa-vaseho-stroje>:8008 uvidíte že Matrix server běži.

Určitě se nechceme vždy připojovat na http://<ip-adresa-vaseho-stroje>:8008. To by bylo poněkud nepohodlné a pravděpodobně by to fungovalo jen v lokální síti. Ještě bychom mohli přesměrovat porty na router, ale to je prašť jako uhoď.

Lepší bude použít doménu jako matrix.nasedomena.eu a samozřejmě https protokol, aby naše data po internetu nelítala jen tak.

Bude to chtít zařídit několik věcí.

  • Je potřeba mít veřejnou statickou IP.
  • Koupit nějakou doménu.
  • Vyřídit si certifikát. Například přes službu Let's Encrypt.
  • Zprovoznit reverzní proxy, která bude zpracovávat příchozí požadavky. Pro tento článek použijeme webový server Nginx jako reverzní proxy. Jak zprovoznit Nginx jako reverzní proxy najdete v článku na tomto webu.

Budeme chtít používat https://matrix.nasedomena.eu a https://element.nasedomena.eu.

Pro element.nasedomena.eu bude konfigurační soubor pro Nginx vypadat nějak takhle.

 server {
    listen 80;
    server_name element.nasedomena.eu;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name element.nasedomena.eu;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/nasedomena.eu/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/nasedomena.eu/privkey.pem; # managed by Certbot

    location / {
        proxy_pass http://192.168.1.111:80;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Veškerý nešifrovaný provoz směrující na element.nasedomena.eu bude přesměrován na šifrovaný.

Pro samotný Matrix server je nutné do konfigurace přidat ještě pár věcí.

server {
    listen 80;
    server_name matrix.nasedomena.eu;
    return 301 https://$host$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.nasedomena.eu;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/nasedomena.eu/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/nasedomena.eu/privkey.pem; # managed by Certbot

     location /.well-known/matrix/client {
                return 200 '{"m.server": {"base_url": "matrix.nasedomena.eu:443"}}';
                default_type application/json;
                add_header Access-Control-Allow-Origin *;
        }

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

    location / {
        proxy_pass http://192.168.1.111:8008;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Jestli máme všechno dobře nakonfigurováno, můžeme zkusit https://element.nasedomena.eu. Poběží tu webový klient pro Matrix. Budeme muset upravit domovský server na náš matrix.nasedomena.eu, protože v základu je tam nastavený matrix.org. Poté se můžeme přihlásit jako uživatel, kterého jsme vytvořili v jednom z předchozích kroků.

K připojení můžete samozřejmě využít jakéhokoliv klienta Matrixu. Přidejte další další uživatele pomocí kroků výše a můžete začít komunikovat naprosto soukromě. Komunikace s dalšími uživateli v rámci Fediverse je také možná. Samotný Synapse jde různě nakonfigurovat. Můžete například povolit registraci uživatelů přes klienty a další možnosti. Konfigurace Synapse ale není náplní tohoto článku.

Loading