Element.io: A Tua Conversa é Tua, e Não do Departamento de Justiça Americano – Parte 2/2

Olá a todos.

Este post é a continuação do da semana passada, intitulado:  Element.io: A Tua Conversa é Tua, e Não do Departamento de Justiça Americano – Parte 1/2

Agora que já expliquei o meu motivo pelo qual estou a fazer isto,e já vos convenci (ou pelo menos plantei a semente da dúvida). Agora vamos ao prático.

O que vamos montar é isto: um servidor Synapse (o homeserver Matrix de referência), com uma base de dados PostgreSQL porque o SQLite que vem por defeito não é para produção, e a interface web do Element a apontar para o vosso servidor. Tudo via Docker Compose, tudo numa máquina que controlam.

Requisitos mínimos:

  • Um servidor Linux (Debian 12 recomendado)
  • Docker + Docker Compose instalados
  • Um domínio próprio com acesso ao DNS
  • Portas 80 e 443 abertas no firewall, preferencialmente por detrás de um reverse proxy caso decidam não utilizar o caddy.
  • 2GB RAM, 2 vCPUs — suficiente para uso familiar ou equipa pequena

Vou assumir que o vosso domínio principal é exemplo.pt e que vão expor o servidor em matrix.exemplo.pt, com o Element em chat.exemplo.pt. Substituam pelos vossos valores reais ao longo do guia.

Passo 1 — Estrutura de Diretórios

Comecem por criar a estrutura de ficheiros que vão usar:

mkdir -p ~/matrix/{synapse,postgres,element}
cd ~/matrix

Simples. O Synapse vai guardar a sua configuração e dados em ~/matrix/synapse, o Postgres em ~/matrix/postgres, e o config do Element em ~/matrix/element.

Passo 2 — Gerar a Configuração Inicial do Synapse

Antes de escrever o docker-compose.yml, precisam de gerar o ficheiro de configuração base do Synapse. Façam isto:

docker run -it --rm \
  -v ~/matrix/synapse:/data \
  -e SYNAPSE_SERVER_NAME=matrix.exemplo.pt \
  -e SYNAPSE_REPORT_STATS=no \
  matrixdotorg/synapse:latest generate

Este comando arranca um container descartável que gera o homeserver.yaml e as chaves de assinatura em ~/matrix/synapse. O SYNAPSE_REPORT_STATS=no é a minha preferência — não envio estatísticas anónimas para o Matrix.org. Podem por yes se quiserem apoiar o projeto com dados agregados.

Verifiquem que os ficheiros foram criados:

ls ~/matrix/synapse/
# homeserver.yaml  matrix.exemplo.pt.log.config  matrix.exemplo.pt.signing.key

Passo 3 — O docker-compose.yml

Criem o ficheiro principal:

vi ~/matrix/docker-compose.yml

Conteúdo:

version: "3.8"

services:    postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      - POSTGRES_DB=synapse
      - POSTGRES_USER=synapse
      - POSTGRES_PASSWORD=MUDA_ESTA_PASSWORD_AGORA
      - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
    volumes:
      - ./postgres:/var/lib/postgresql/data
    networks:
      - matrix_net

  synapse:
    image: matrixdotorg/synapse:latest
    restart: unless-stopped
    depends_on:
      - postgres
    volumes:
      - ./synapse:/data     networks:
      - matrix_net

  element:
    image: vectorim/element-web:latest
    restart: unless-stopped
    volumes:
      - ./element/config.json:/app/config.json:ro
    networks:
      - matrix_net

  caddy:
    image: caddy:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - matrix_net

volumes:
  caddy_data:
  caddy_config:

networks:
  matrix_net:
    driver: bridge

Algumas notas sobre as escolhas aqui:

Usei Caddy como reverse proxy em vez de Nginx porque o Caddy gere os certificados Let’s Encrypt automaticamente, sem configuração adicional. Para quem não é sysadmin de profissão, isto faz uma diferença enorme. O Nginx funciona igualmente bem, mas requer que configurem o Certbot separadamente — mais um passo, mais um serviço, mais coisas para gerir.

O Postgres 16 em vez do SQLite é obrigatório para qualquer coisa além de testes. O SQLite não aguenta escrita concorrente com a frequência que um servidor Matrix gera.

Passo 4 — Configurar o homeserver.yaml

Agora a parte que requer atenção. Abram o ficheiro de configuração que foi gerado:

vi ~/matrix/synapse/homeserver.yaml

Encontrem a secção da base de dados e substituam o bloco SQLite pelo PostgreSQL:

# Comentem ou apaguem isto:
# database:
#   name: sqlite3
#   args: #     database: /data/homeserver.db

# Adicionem isto em substituição:
database:
  name: psycopg2
  args:
    user: synapse
    password: MUDA_ESTA_PASSWORD_AGORA
    database: synapse
    host: postgres
    cp_min: 5
    cp_max: 10

A password tem de ser a mesma que puseram na variável POSTGRES_PASSWORD no docker-compose.yml. Não se esqueçam.

Outras configurações importantes no homeserver.yaml:

# Desativar registo público — qualquer pessoa poderia criar conta no vosso servidor
enable_registration: false

# Se quiserem permitir registo por convite ou token, usem isto em vez do acima:
# enable_registration: true
# registration_requires_token: true

# URL pública do servidor
public_baseurl: https://matrix.exemplo.pt/

# Tamanho máximo de uploads (ajustem ao vosso gosto)
max_upload_size: 50M

O enable_registration: false é crítico. Com isto desativado, ninguém cria conta no vosso servidor sem que vocês criem manualmente. Para uso familiar ou empresarial fechado, é o que querem.

Passo 5 — Configurar o Element Web

Criem o ficheiro de configuração do Element:

vi ~/matrix/element/config.json
{
  "default_server_config": {
    "m.homeserver": {
      "base_url": "https://matrix.exemplo.pt",       "server_name": "matrix.exemplo.pt"
    }
  },
  "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"
  ],
  "bug_report_endpoint_url": "https://element.io/bugreports/submit",
  "features": {},
  "show_labs_settings": true,
  "default_theme": "light"
}

Se quiserem apontar o Element para o vosso homeserver por defeito (sem os utilizadores terem de o configurar manualmente), o campo base_url é o que faz isso. Os utilizadores abrem chat.exemplo.pt e já está apontado para o vosso servidor.

Passo 6 — O Caddyfile

O Caddy precisa de saber como fazer o routing. Criem:

vi ~/matrix/Caddyfile
matrix.exemplo.pt {
  reverse_proxy /_matrix/* synapse:8008
  reverse_proxy /_synapse/client/* synapse:8008

  header {
    X-Content-Type-Options nosniff
    X-Frame-Options SAMEORIGIN
    Strict-Transport-Security "max-age=63072000; includeSubDomains"
    X-XSS-Protection "1; mode=block"
  }
}

chat.exemplo.pt {
  reverse_proxy element:80

  header {
    X-Content-Type-Options nosniff
    X-Frame-Options SAMEORIGIN
    Strict-Transport-Security "max-age=63072000; includeSubDomains"
  }
}

O Caddy vai automaticamente obter certificados TLS válidos para ambos os domínios via Let’s Encrypt. Não precisam de fazer mais nada — só garantir que os registos DNS apontam para o IP do servidor antes de arrancarem.

Passo 7 — DNS

No vosso registrar/painel DNS, adicionem dois registos A:

matrix.exemplo.pt  →  IP_DO_VOSSO_SERVIDOR
chat.exemplo.pt    →  IP_DO_VOSSO_SERVIDOR

Se quiserem que os vossos utilizadores tenham IDs do tipo @nome:exemplo.pt (em vez de @nome:matrix.exemplo.pt), precisam de um passo adicional de delegação — mas isso é tema para um how-to separado.

Passo 8 — Arrancar Tudo (e fazer figas)

cd ~/matrix
docker compose up -d

Aguardem uns 30 segundos e verifiquem se está tudo a correr:

docker compose ps

Devem ver os quatro serviços (postgres, synapse, element, caddy) com estado Up. Para ver os logs do Synapse em tempo real:

docker compose logs -f synapse

Passo 9 — Criar o Primeiro Utilizador

Com enable_registration: false, as contas têm de ser criadas manualmente. Façam assim:

docker compose exec synapse register_new_matrix_user \
  -c /data/homeserver.yaml \
  http://localhost:8008

O comando vai pedir nome de utilizador, password, e se é administrador (yes para o primeiro utilizador — vão precisar de acesso admin para gerir o servidor).

Depois disto, vão a https://chat.exemplo.pt, façam login com as credenciais que acabaram de criar, e o Element já está a comunicar com o vosso servidor.

Passo 10 — Manutenção e Atualizações

Para atualizar as imagens quando saírem novas versões:

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

Simples assim. O Docker Compose vai recriar os containers com as novas imagens, mantendo todos os dados nos volumes.

Para backups, o essencial é preservar:

  • ~/matrix/postgres/ — a base de dados
  • ~/matrix/synapse/ — a configuração e as chaves de assinatura (as chaves são especialmente importantes — sem elas não conseguem recuperar o servidor)

O que ficou de fora deste guia

Há coisas que deixei propositadamente de fora para não tornar isto avassalador:

TURN server para chamadas de voz/vídeo: Para chamadas que atravessem NAT (que é a maioria das situações reais), precisam de um servidor TURN. O coturn é a solução standard e tem imagem Docker. Vou escrever sobre isso separadamente.

Bridges para outros serviços: Se quiserem que o vosso Element receba mensagens do WhatsApp, Telegram ou Slack, há bridges para tudo isso. São containers adicionais que se ligam ao Synapse. O mxWhatsApp e o mautrix-telegram são os mais maduros.

Delegação de domínio: Se querem IDs @nome:exemplo.pt em vez de @nome:matrix.exemplo.pt, há um passo de configuração adicional com ficheiros .well-known no domínio raiz.

Element Server Suite Pro: Se estão a avaliar o Element para contexto empresarial mais exigente, a versão Pro da Element HQ adiciona gestão centralizada de utilizadores, políticas de retenção configuráveis e integrações SSO que vão além do que este setup cobre. Para uma PME ou empresa com 50+ utilizadores, vale a pena avaliar.

Se tiverem questões ou ficarem presos em algum passo, deixem um comentário. Isto é exactamente o tipo de coisa que gosto de resolver.

Um abraço, Nuno

Categorias: Segurança · On-premise · How-To’s · Pensamentos · Europe