Twaalf builds

Een Matrix-homeserver waarvan federatie echt werkt

Synapse op een kleine Ryzen-instance met Postgres, delegatie via well-known-bestanden in plaats van SRV-records, en verificatie die andere servers bereikt.

Wat dit bouwt

Een homeserver op example.com, draaiend op matrix.example.com, die correct federation met iedereen. Postgres eronder, nginx ervoor, delegatie afgehandeld door twee kleine JSON-bestanden, en registratie gesloten zodat jouw server niet binnen een week iemands gratis relay wordt.

Federation is waar deze installaties meestal falen, en bijna nooit vanwege Synapse. De server draait, lokale berichten werken, en dan komt er niets van buiten aan. In de praktijk is de oorzaak bijna altijd delegatie: de identiteit van de server en het adres waar hij woont zijn twee verschillende dingen, en het mechanisme dat ze verbindt is makkelijk subtiel fout te doen.

Voordat je begint

  • Een R-4 is genoeg voor een paar dozijn gebruikers. Synapse is meer geheugenhongerig dan CPU-hongerig, en het toetreden tot grote federatieve kamers is het enige waar hij van gaat zweten.
  • Twee namen in DNS: example.com, de identiteit van je server die in elke gebruikers-id verschijnt, en matrix.example.com, waar de software daadwerkelijk luistert.
  • Certificaten voor beide. De eerste hoeft slechts twee statische bestanden te dienen.

1. Database, met de juiste collatie

apt update && apt install -y postgresql matrix-synapse nginx certbot
sudo -u postgres psql -c "CREATE USER synapse_user WITH PASSWORD '<a long password>';"
sudo -u postgres psql -c "CREATE DATABASE synapse ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE=template0 OWNER synapse_user;"

De collatie is geen detail. Synapse weigert te starten op een database die is aangemaakt met een andere collatie dan C, en de fout die het afdrukt als je dit fout doet, komt pas nadat je al gegevens hebt geïmporteerd. Doe het nu, correct, één keer.

2. Homeserver-configuratie

Debian's pakket vraagt tijdens installatie om de servernaam; antwoord example.com, niet de hostnaam van de machine. Dat antwoord wordt onderdeel van elke gebruikers-id en kamer-id op de server en kan achteraf niet worden gewijzigd zonder de server achter te laten.

Bewerk dan /etc/matrix-synapse/homeserver.yaml:

server_name: "example.com"
public_baseurl: "https://matrix.example.com/"
pid_file: /run/matrix-synapse.pid

listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true
    bind_addresses: ['127.0.0.1']
    resources:
      - names: [client, federation]
        compress: false

database:
  name: psycopg2
  args:
    user: synapse_user
    password: "<a long password>"
    database: synapse
    host: 127.0.0.1
    cp_min: 5
    cp_max: 10

enable_registration: false
registration_shared_secret: "<a long random string>"
report_stats: false
suppress_key_server_warning: true
url_preview_enabled: false

media_store_path: /var/lib/matrix-synapse/media
max_upload_size: 100M
media_retention:
  remote_media_lifetime: 30d

rc_message:
  per_second: 0.5
  burst_count: 15

Twee van die instellingen besparen je schijf en verdriet. Remote-media-retentie verwijdert gecachte kopieën van bestanden van andere servers na een maand, en zonder dit groeit je mediaopslag voor altijd met inhoud waar je nooit om hebt gevraagd. URL-previews staan uit omdat ze je server willekeurige adressen laten ophalen namens iedereen die een link kan plaatsen, wat een request-forgery-motor is met een chatinterface eraan.

x_forwarded: true is ook belangrijk: zonder dit rate-limits Synapse elke gebruiker ter wereld alsof het één client is, omdat elk verzoek van nginx lijkt te komen.

3. Delegatie

Je identiteit is example.com en je server staat op matrix.example.com. Twee bestanden overbruggen de kloof. Serveer ze vanaf example.com, via HTTPS, met het juiste content-type.

/.well-known/matrix/server:

{ "m.server": "matrix.example.com:443" }

/.well-known/matrix/client:

{ "m.homeserver": { "base_url": "https://matrix.example.com" } }

De poort in het eerste bestand is verplicht. Laat hem weg en andere servers vallen terug op poort 8448, vinden niets luisteren, en geven stilletjes op; je gebruikers melden dan dat federation kapot is terwijl elk log op je machine er volkomen gezond uitziet.

server {
  listen 443 ssl;
  server_name example.com;
  ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

  location /.well-known/matrix/ {
    root /var/www/wellknown;
    default_type application/json;
    add_header Access-Control-Allow-Origin *;
  }
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name matrix.example.com;
  ssl_certificate     /etc/letsencrypt/live/matrix.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/matrix.example.com/privkey.pem;
  client_max_body_size 100m;

  location ~ ^(/_matrix|/_synapse/client) {
    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;
  }
}

De Access-Control-Allow-Origin-header op de well-known-locatie is vereist voor webclients en wordt door bijna iedereen vergeten. Zonder hem werken desktopclients en kunnen browserclients je server helemaal niet vinden.

mkdir -p /var/www/wellknown/.well-known/matrix
systemctl restart matrix-synapse nginx

4. Een gebruiker

register_new_matrix_user -c /etc/matrix-synapse/homeserver.yaml http://127.0.0.1:8008

Beantwoord de aanwijzingen, maak het eerste account een admin en laat open registratie uit. Een homeserver met open registratie is binnen dagen een spam-bron, en andere servers zullen verkeer van jou weigeren lang voordat je het merkt.

Verifieer het

Werken van buiten naar binnen. Ten eerste, antwoord de software ergens op:

curl -s https://matrix.example.com/_matrix/client/versions | head -c 200
curl -s https://matrix.example.com/_matrix/federation/v1/version

Is delegatie dan correct geserveerd, met de poort aanwezig en het content-type goed:

curl -si https://example.com/.well-known/matrix/server | grep -E "content-type|m.server"
curl -s https://example.com/.well-known/matrix/client

Resolveert je ondertekeningssleutel dan. Andere servers halen dit op voordat ze überhaupt met je praten:

curl -s https://matrix.example.com/_matrix/key/v2/server | head -c 300

Tot slot, de enige test die telt. Log in met een client, word lid van een openbare kamer op een homeserver die niet de jouwe is, en stuur een bericht. Lees dan federation-status van de admin-API, met de access token die je client in zijn instellingen toont:

curl -s -H "Authorization: Bearer <admin token>" \
  "https://matrix.example.com/_synapse/admin/v1/federation/destinations" | head -c 400

Elke bestemming moet een recent succesvol transactie en geen retry-interval tonen. Bestemmingen met een groeiende retry_interval zijn servers die jij niet kunt bereiken; als elke bestemming er zo uitziet, is het probleem delegatie in plaats van het netwerk, en stap drie is waar je moet kijken.

journalctl -u matrix-synapse --since "10 min ago" | grep -i "federation" | tail -20

Hierna

De eerste keer dat je lid wordt van een zeer grote kamer, zal een kern gedurende enkele minuten vastpinnen en veel status binnenhalen. Dat is normaal, het gebeurt één keer per kamer, en het is de belangrijkste reden waarom mensen concluderen dat Synapse langzaam is. Spraak en video hebben een TURN-server naast deze; coturn op hetzelfde exemplaar kan een kleine gemeenschap aan, hoewel het zijn eigen UDP-poortbereik in de firewall wil. Federation praat veel in beide richtingen, wat het onthouden waard is bij het kiezen van de site: onze locatie-index vermeldt de round-trip-tijden die we zelf meten.

Klaar wanneer jij dat bent

Kies een stad. Kies een formaat. Betaal in munt.

Geen formulieren over wie je bent, geen wachten op een mens die je goedkeurt, geen telefoontje om iets te verifiëren. De factuur wordt betaald en de inloggegevens belanden in je inbox.