Doze construções

Um homeserver Matrix cuja federação realmente funciona

Synapse em uma pequena instância Ryzen com Postgres, delegação feita através de arquivos well-known em vez de registros SRV, e verificação que alcança outros servidores.

O que este guia constrói

Um servidor doméstico em example.com, rodando em matrix.example.com, federando corretamente com todos os demais. Postgres por baixo, nginx na frente, delegação tratada por dois pequenos arquivos JSON e registro fechado, para que seu servidor não se torne o retransmissor gratuito de alguém em uma semana.

A federação é onde essas instalações costumam falhar, e quase nunca por causa do Synapse. O servidor roda, mensagens locais funcionam, e então nada de fora chega. Na prática, a causa é quase sempre a delegação: a identidade do servidor e o endereço onde ele vive são duas coisas diferentes, e o mecanismo que as conecta é fácil de errar sutilmente.

Antes de começar

  • Um R-4 é suficiente para algumas dezenas de usuários. O Synapse consome mais memória do que CPU, e entrar em grandes salas federadas é a única coisa que o faz suar.
  • Dois nomes no DNS: example.com, que é a identidade do seu servidor e aparece em cada ID de usuário, e matrix.example.com, onde o software realmente escuta.
  • Certificados para ambos. O primeiro só precisa servir dois arquivos estáticos.

1. Banco de dados, com a collation correta

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;"

A collation não é um detalhe. O Synapse se recusa a iniciar em um banco de dados criado com qualquer collation que não seja C, e o erro que ele imprime quando você erra isso chega depois de você já ter importado dados. Faça isso agora, corretamente, uma vez.

2. Configuração do homeserver

O pacote do Debian pede o nome do servidor durante a instalação; responda example.com, não o hostname da máquina. Essa resposta se torna parte de cada ID de usuário e de sala no servidor e não pode ser alterada depois sem abandonar o servidor.

Em seguida, edite /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

Duas dessas configurações economizam disco e aborrecimentos. A retenção de mídia remota descarta cópias em cache de arquivos de outros servidores após um mês, e sem ela seu armazenamento de mídia cresce para sempre com conteúdo que você nunca pediu. As pré-visualizações de URL estão desativadas porque fazem seu servidor buscar endereços arbitrários em nome de qualquer pessoa que possa postar um link, o que é um motor de falsificação de requisições com uma interface de chat anexada.

x_forwarded: true também importa: sem ela, o Synapse limita a taxa de todos os usuários do mundo como se fossem um único cliente, porque toda requisição parece vir do nginx.

3. Delegação

Sua identidade é example.com e seu servidor está em matrix.example.com. Dois arquivos preenchem a lacuna. Sirva-os em example.com, via HTTPS, com o tipo de conteúdo correto.

/.well-known/matrix/server:

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

/.well-known/matrix/client:

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

A porta no primeiro arquivo é obrigatória. Se omiti-la, outros servidores caem na porta 8448, não encontram nada escutando e desistem silenciosamente; então seus usuários reportam que a federação está quebrada enquanto todos os logs da sua máquina parecem saudáveis.

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;
  }
}

O cabeçalho Access-Control-Allow-Origin no local well-known é exigido pelos clientes web e esquecido por quase todo mundo. Sem ele, clientes desktop funcionam e clientes de navegador não conseguem encontrar seu servidor de forma alguma.

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

4. Um usuário

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

Responda aos prompts, torne a primeira conta um administrador e deixe o registro aberto desativado. Um homeserver com registro aberto vira uma fonte de spam em dias, e outros servidores começarão a recusar seu tráfego muito antes de você notar.

Verifique

Trabalhe de dentro para fora. Primeiro, o software está respondendo:

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

Depois, a delegação está sendo servida corretamente, com a porta presente e o tipo de conteúdo certo:

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

Então, sua chave de assinatura resolve. Outros servidores a buscam antes de aceitar conversar com você:

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

Finalmente, o único teste que importa. Faça login com um cliente, entre em uma sala pública hospedada em um homeserver que não é o seu e envie uma mensagem. Então leia o estado da federação pela API administrativa, usando o token de acesso que seu cliente mostra nas configurações:

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

Cada destino deve mostrar uma transação recente bem-sucedida e nenhum intervalo de nova tentativa. Destinos com retry_interval crescente são servidores que você não consegue alcançar; se todos os destinos parecerem assim, o problema é delegação, não rede, e o passo três é onde procurar.

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

Depois

Entrar em uma sala muito grande pela primeira vez vai pinar um núcleo por vários minutos e puxar uma grande quantidade de estado. Isso é normal, acontece uma vez por sala, e é a principal razão pela qual as pessoas concluem que o Synapse é lento. Voz e vídeo precisam de um servidor TURN ao lado deste; coturn na mesma instância atende a uma pequena comunidade, embora queira sua própria faixa de portas UDP no firewall. A federação é conversada nas duas direções, o que vale lembrar ao escolher o local: nosso índice de locais lista os tempos de ida e volta que medimos nós mesmos.

Pronto quando você estiver

Escolha uma cidade. Escolha um tamanho. Pague em cripto.

Sem formulários sobre quem você é, sem esperar aprovação de um humano, sem ligação para verificar nada. O pagamento é confirmado e as credenciais chegam na sua caixa de entrada.