Domínio, HTTPS e proxies reversos

Coloque o Antimatter em um nome de domínio com HTTPS, usando o perfil Caddy do arquivo compose ou um proxy reverso próprio, e configure corretamente a URL do site e os endereços dos clientes.

A URL do site

A URL do site (ServiceSettings.SiteURL) é o endereço que as pessoas usam para acessar o Antimatter, como https://chat.example.com. O servidor a usa em links de e-mails e notificações, em redirecionamentos de login (OAuth, OpenID Connect, SAML), para os aplicativos móveis e de desktop, e para verificar de onde vêm as solicitações. Defina-a exatamente como o endereço na barra de endereços do navegador: esquema, domínio e porta (se não for a padrão), sem barra no final.

  • Com o arquivo compose do site: SITE_URL em .env.
  • Em qualquer outro lugar: AM_SERVICESETTINGS_SITEURL, ou Console do Sistema › Ambiente › Servidor Web › Site URL.

Se a URL do site estiver incorreta, o login com um provedor de identidade falhará, os links nos e-mails apontarão para o lugar errado e os aplicativos podem não se conectar. Após alterar o domínio, atualize-a aqui e nas URLs de redirecionamento de todos os provedores de identidade.

HTTPS com o perfil Caddy incluído

O arquivo compose.yaml do site inclui um serviço Caddy no perfil https. Ele obtém um certificado da Let's Encrypt, renova-o automaticamente, redireciona HTTP para HTTPS e encaminha tudo, incluindo websockets, para o Antimatter.

  1. Aponte um registro DNS (A, e AAAA para IPv6) do seu domínio para o servidor.
  2. Abra as portas 80/tcp, 443/tcp e 443/udp (HTTP/3) no firewall. A Let's Encrypt deve conseguir acessar a porta 80 ou 443 a partir da Internet.
  3. Adicione o domínio ao .env e defina a URL do site:
    echo "DOMAIN=chat.example.com" >> .env
    sed -i 's|^SITE_URL=.*|SITE_URL=https://chat.example.com|' .env
  4. Inicie com o perfil:
    docker compose --profile https up -d

Adicione --profile https a cada docker compose up subsequente, ou coloque COMPOSE_PROFILES=https em .env para que um simples docker compose up -d o inclua. O Caddy mantém seus certificados no volume https.

A própria porta do Antimatter continua publicada no host (HTTP_PORT, 8065 por padrão). Com o Caddy na frente, mantenha-a apenas para o próprio servidor:

echo "HTTP_PORT=127.0.0.1:8065" >> .env
docker compose --profile https up -d

O Caddy acessa o Antimatter pela rede interna edge, não por essa porta, então isso não muda nada para seus usuários.

Com seu próprio proxy reverso (nginx)

Se o servidor já executa nginx ou outro proxy, desative o perfil https e aponte o proxy para a porta 8065 do Antimatter. O proxy deve:

  • transmitir as atualizações de websocket (o aplicativo web e os aplicativos móveis mantêm um websocket aberto em /api/v4/websocket, e alguns aplicativos abrem os seus próprios);
  • aceitar corpos de solicitação pelo menos do tamanho do maior upload (Tamanho Máximo do Arquivo, 100 MB por padrão);
  • manter conexões de longa duração abertas (websockets, uploads e downloads grandes);
  • transmitir o cabeçalho Host e o endereço do cliente.

Um bloco de servidor completo, adaptado do modelo de produção em antimatter-docker. Substitua o domínio e os caminhos dos certificados:

upstream antimatter {
    server 127.0.0.1:8065;
    keepalive 64;
}

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      '';
}

proxy_cache_path /var/cache/nginx/antimatter levels=1:2 keys_zone=antimatter_cache:10m
                 max_size=3g inactive=120m use_temp_path=off;

server {
    listen 80;
    listen [::]:80;
    server_name chat.example.com;
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name chat.example.com;

    ssl_certificate     /etc/ssl/chat.example.com/fullchain.pem;
    ssl_certificate_key /etc/ssl/chat.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_timeout 1d;
    ssl_session_cache shared:AntimatterSSL:10m;
    ssl_session_tickets off;

    add_header Strict-Transport-Security "max-age=31536000" always;

    # At least FileSettings.MaxFileSize (100 MB by default).
    client_max_body_size 100M;

    proxy_http_version 1.1;
    proxy_set_header Host              $host;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Upgrade           $http_upgrade;
    proxy_set_header Connection        $connection_upgrade;
    proxy_buffers 256 16k;
    proxy_buffer_size 16k;

    location ~ ^/api/v[0-9]+/(users/)?websocket$ {
        client_body_timeout 60s;
        send_timeout 300s;
        lingering_timeout 5s;
        proxy_connect_timeout 90s;
        proxy_send_timeout 300s;
        proxy_read_timeout 90s;
        proxy_pass http://antimatter;
    }

    location / {
        proxy_read_timeout 600s;
        proxy_cache antimatter_cache;
        proxy_cache_revalidate on;
        proxy_cache_min_uses 2;
        proxy_cache_use_stale timeout;
        proxy_cache_lock on;
        proxy_pass http://antimatter;
    }
}

Verifique o arquivo com nginx -t e aplique-o com systemctl reload nginx. O servidor envia X-Content-Type-Options, Referrer-Policy, Permissions-Policy e X-Frame-Options por conta própria; apenas o HSTS fica a cargo do proxy. Aumente o max-age quando o HTTPS estiver funcionando e adicione includeSubDomains apenas se todos os subdomínios usarem HTTPS.

Com Docker Compose e nginx no host, o upstream acima aponta para a porta 8065 publicada. Publique-a apenas em 127.0.0.1 (HTTP_PORT=127.0.0.1:8065), para que ninguém contorne o proxy.

O repositório antimatter-docker tem uma configuração completa com nginx em um contêiner e Let's Encrypt através do certbot, em deploy/compose.

Outros proxies

Qualquer proxy funciona se atender aos quatro pontos acima. As chamadas de áudio e vídeo nunca passam pelo proxy: elas usam a própria porta, veja Chamadas e voz.

Endereços de clientes atrás de um proxy

Atrás de um proxy, todas as solicitações parecem vir do proxy. Para registrar o endereço real do cliente, aplicar limites de taxa por cliente e usar filtragem de IP, informe ao servidor qual cabeçalho carrega o endereço e quais proxies ele pode confiar. Nenhuma dessas configurações tem um campo no Console do Sistema: defina-as em config.json ou com variáveis.

Chave e variávelPadrãoO que faz
ServiceSettings.TrustedProxyIPHeader, AM_SERVICESETTINGS_TRUSTEDPROXYIPHEADERvazio: o servidor usa o endereço da conexãoOs cabeçalhos que carregam o endereço do cliente, por exemplo X-Forwarded-For. O primeiro presente em uma solicitação é usado.
ServiceSettings.TrustedProxyIPs, AM_SERVICESETTINGS_TRUSTEDPROXYIPSvazioOs endereços ou faixas CIDR dos seus proxies, por exemplo 172.29.71.0/28. Os cabeçalhos só valem para solicitações que vêm de um deles.

Em uma variável, separe vários valores com espaços: AM_SERVICESETTINGS_TRUSTEDPROXYIPHEADER="X-Forwarded-For X-Real-IP". O servidor rejeita uma configuração com uma entrada em TrustedProxyIPs que não seja um endereço IP nem uma faixa CIDR.

Como o servidor encontra o endereço do cliente

Cada proxy adiciona o endereço de onde recebeu a solicitação à direita de X-Forwarded-For. O que o cliente enviou no próprio cabeçalho permanece à esquerda. Assim, o servidor lê o cabeçalho da direita para a esquerda, ignora os endereços dos seus proxies confiáveis e usa o primeiro outro endereço como o do cliente. Um cliente não pode escolher seu endereço enviando seu próprio cabeçalho.

  • Atrás de um proxy, TrustedProxyIPHeader sozinho fornece o endereço correto: o servidor usa o endereço mais à direita do cabeçalho. Ele registra um aviso na inicialização até que você também configure TrustedProxyIPs. Sem isso, qualquer pessoa que acesse a porta 8065 diretamente pode definir o cabeçalho, então publique essa porta apenas em 127.0.0.1 ou em uma rede privada.
  • Atrás de vários proxies, por exemplo, um CDN ou um balanceador de carga à frente do seu próprio proxy, liste todos eles em TrustedProxyIPs. Caso contrário, o servidor usará o endereço do proxy externo como o do cliente.
  • O proxy pode substituir o cabeçalho com o endereço que vê, como no exemplo do nginx acima (X-Forwarded-For $remote_addr), ou adicioná-lo ao existente (o $proxy_add_x_forwarded_for do nginx). Ambos funcionam.

Quais endereços listar

Liste o endereço de onde as solicitações do proxy vêm, conforme visto pelo Antimatter.

  • Com o arquivo compose do site e o Caddy, isso já está feito: o Caddy acessa o Antimatter pela rede edge, e o arquivo compose define TrustedProxyIPHeader como X-Forwarded-For e TrustedProxyIPs como a faixa dessa rede, EDGE_SUBNET (172.29.71.0/28, a menos que você a altere no .env). Altere EDGE_SUBNET se ela sobrepor uma das suas redes.
  • A configuração de produção no antimatter-docker faz o mesmo para seu contêiner nginx, com FRONTEND_SUBNET.
  • Com nginx no host e Antimatter no Docker, as solicitações chegam ao Antimatter através da porta publicada, geralmente a partir do endereço do gateway da rede do projeto compose (visível com docker network inspect). Defina AM_SERVICESETTINGS_TRUSTEDPROXYIPS com esse endereço no compose.override.yaml.
  • Sem Docker, com nginx no mesmo host, é 127.0.0.1 (e ::1 se o nginx se conectar via IPv6).

TLS sem proxy

O servidor também pode fornecer HTTPS por conta própria, em Console do Sistema › Ambiente › Servidor Web: Segurança da Conexão definido como TLS (ServiceSettings.ConnectionSecurity), com Arquivo de Certificado TLS e Arquivo da Chave TLS (ServiceSettings.TLSCertFile, ServiceSettings.TLSKeyFile), ou Usar Let's Encrypt (ServiceSettings.UseLetsEncrypt). O servidor deve então escutar na porta 443 (Endereço à Escutar, ServiceSettings.ListenAddress, :8065 por padrão), e ServiceSettings.Forward80To443 redireciona a porta 80. Um proxy reverso é mais fácil de executar e renovar, e é o que este guia pressupõe.

Tempos limite do servidor e tamanho da solicitação

Configurações do próprio servidor web do servidor, em Console do Sistema › Ambiente › Servidor Web:

ConfiguraçãoChavePadrão
Endereço à EscutarServiceSettings.ListenAddress:8065
Tempo limite de escritaServiceSettings.ReadTimeout300 segundos
Tempo limite de gravaçãoServiceSettings.WriteTimeout300 segundos
Tempo limite de ociosidade (sem campo no Console do Sistema)ServiceSettings.IdleTimeout60 segundos
Tamanho máximo de payload (bytes)ServiceSettings.MaximumPayloadSizeBytesveja Segurança

Mantenha os tempos limite do próprio proxy pelo menos tão longos quanto estes para solicitações normais, e o tamanho do corpo pelo menos Tamanho Máximo do Arquivo.