Primeiros passos
Ao final você terá uma instância do Decoding Chat em um hostname seu, rodando o app web, a API HTTP, o Gateway, o painel de administração, uploads, busca e sinalização de voz em contêineres Docker em uma única máquina. Reserve cerca de 30 minutos, a maior parte gasta baixando imagens.
O que você precisa
Seção intitulada “O que você precisa”| Requisito | Valor |
|---|---|
| Host | Qualquer máquina que rode Docker com contêineres Linux. Um servidor Linux, ou um Mac ou PC Windows com Docker Desktop |
| Runtime | Docker Engine 24 ou mais novo, ou Podman 5 ou mais novo, com o plugin Compose v2.20.2 ou mais novo |
| Processador | Intel, AMD e Apple Silicon funcionam. Toda imagem é publicada para amd64 e arm64, e o Docker baixa a correspondente |
| CPU | 2 vCPU no mínimo, 4 vCPU para uma comunidade pequena e ativa. Nenhum serviço define limite de CPU, então todo contêiner enxerga todas |
| RAM | 8 GB no mínimo com os padrões de fábrica, 16 GB para uma comunidade pequena e ativa. Com 4 GB são necessários os ajustes de pouca memória |
| Disco | 20 GB no mínimo, mais que isso para uploads |
| Portas de entrada | 80/tcp, 443/tcp e 443/udp para a camada web, mais 7881/tcp e 7882/udp para a mídia de voz |
| DNS | Um registro A do hostname apontando para esta máquina, e opcionalmente um AAAA |
| Saída | Resolução de DNS funcionando de dentro dos contêineres |
| Ferramentas no host | curl e openssl no Linux. O macOS já traz os dois. O instalador do Windows não precisa de nenhum |
Limites de memória são tetos, não reservas. Em um host de 4 GB, reduza primeiro os limites de api e worker. Com Docker Desktop, verifique a RAM atribuída à máquina virtual Linux dele, e não o total do host.
A stack é um único projeto Compose. A borda e o LiveKit são os únicos serviços que publicam portas.
Os passos abaixo usam o Caddy que vem junto, que obtém e renova o certificado TLS do hostname e não exige configuração. Para colocar seu próprio proxy na frente, adicione o overlay docker-compose.proxy.yml. A stack então deixa a 80 e a 443 em paz e publica uma porta HTTP simples para o seu proxy encaminhar. Atrás do seu próprio proxy reverso traz o overlay, os requisitos e configurações prontas para nginx, Caddy, Traefik, HAProxy, Apache, Cloudflare Tunnel e Nginx Proxy Manager.
Passo 1: instalar o Docker
Seção intitulada “Passo 1: instalar o Docker”Veja o que você já tem:
docker --versiondocker compose versionSe os dois responderem, pule adiante. Em um Mac ou PC Windows, instale o Docker Desktop e deixe-o em contêineres Linux, o que já entrega os dois.
Debian e Ubuntu precisam do repositório apt do Docker, descrito em Install Docker Engine, porque o pacote docker.io da própria distribuição não traz o plugin Compose. Siga os passos pós-instalação para adicionar seu usuário ao grupo docker, depois saia e entre de novo na sessão para que os comandos abaixo rodem sem sudo.
O Linux também precisa de curl e openssl, usados nos passos seguintes:
sudo apt-get install -y curl opensslTroque apt-get por dnf, zypper, pacman ou apk conforme a distribuição. Os nomes dos pacotes são os mesmos, e curl --version e openssl version respondem assim que a instalação termina.
Passo 2: apontar o DNS para o host
Seção intitulada “Passo 2: apontar o DNS para o host”Escolha o hostname em que a instância vai responder. O Passo 4 o escreve no .env como FLUXER_DOMAIN, e todos os exemplos abaixo usam chat.example.com no lugar dele.
Crie um registro A desse hostname apontando para o endereço público da máquina, e um AAAA quando a máquina tiver endereço IPv6 público. Um provedor de hospedagem mostra esse endereço no painel. Em uma conexão residencial, o endereço pertence ao roteador, e a página de status dele mostra qual é.
Passo 3: abrir as portas
Seção intitulada “Passo 3: abrir as portas”Abra estas portas no host:
| Porta | Protocolo | Usada por |
|---|---|---|
| 22 | tcp | SSH, em um host que você acessa remotamente |
| 80 | tcp | Validação HTTP do ACME e redirecionamento para HTTPS |
| 443 | tcp | O app web, a API HTTP, o Gateway e o painel de administração |
| 443 | udp | HTTP/3 para o mesmo tráfego |
| 7881 | tcp | Mídia do LiveKit, publicada pelo contêiner do LiveKit |
| 7882 | udp | Mídia do LiveKit, publicada pelo contêiner do LiveKit |
Uma máquina atrás de roteador residencial precisa da 80, da 443 e das duas portas do LiveKit encaminhadas para ela. O certificado é emitido a partir da internet pública, e a mídia de voz chega direto nas portas do LiveKit. Rodar seu próprio proxy reverso muda apenas as duas primeiras. O proxy fica com elas, e a stack escuta uma porta HTTP simples no loopback. A 7881 e a 7882 precisam alcançar o host de qualquer jeito, porque mídia de voz nunca passa por proxy.
Para usar outra porta, abra ela no lugar da 443 e leia Servindo em outra porta.
Em uma VM na nuvem, abra as portas no firewall ou no grupo de segurança do provedor. Em um host Linux com firewalld:
sudo firewall-cmd --permanent --add-service=sshsudo firewall-cmd --permanent --add-port=80/tcp --add-port=443/tcp --add-port=443/udp \ --add-port=7881/tcp --add-port=7882/udpsudo firewall-cmd --reloadPasso 4: subir a instância
Seção intitulada “Passo 4: subir a instância”O instalador baixa os arquivos da stack, escreve o .env, gera todos os segredos e inicia a instância. Baixe, confira o SHA-256 publicado, leia e só então execute.
No Linux:
curl -fsSLO https://docs.example.com/install.shcurl -fsSLO https://docs.example.com/install.sh.sha256sha256sum -c install.sh.sha256No macOS, os mesmos downloads e:
shasum -a 256 -c install.sh.sha256No Windows:
Invoke-WebRequest https://docs.example.com/install.ps1 -OutFile install.ps1Invoke-WebRequest https://docs.example.com/install.ps1.sha256 -OutFile install.ps1.sha256(Get-FileHash .\install.ps1 -Algorithm SHA256).Hash -eq (Get-Content .\install.ps1.sha256).Split()[0]install.sh: OK no Linux e no macOS, e True no Windows, significam que o arquivo chegou íntegro. O digest da cópia que este site serve é 4e7f16b7ac5d17dd94ca5197f2faa6800f283cd9ab9fe8f011a0716010eee2e3 para o install.sh e 5bcb68326f2efdb65e09a676d72843ad3a94dae119ba76c7221aca31da1c7614 para o install.ps1.
Leia o script antes de rodar. Ele escreve o .env, e esse arquivo guarda todos os segredos da instância.
A execução abaixo usa o TLS que vem junto. Acrescente --tls proxy quando outra coisa terminar o TLS, e leia Atrás do seu próprio proxy reverso antes.
Então execute, com o hostname do Passo 2. O --email vira o endereço de contato no web push de saída:
sh install.sh --domain chat.example.com --email voce@example.comNo Windows:
powershell -ExecutionPolicy Bypass -File .\install.ps1 -Domain chat.example.com -Email voce@example.comA execução imprime uma linha por fase e termina com a URL para abrir.
O diretório ~/fluxer passa a conter docker-compose.yml, docker-compose.proxy.yml, tunnel.compose.yml, Caddyfile e .env.example, além de um .env legível apenas por você. Todo valor que vem como CHANGE_ME no .env.example recebe um valor aleatório novo. Todos os comandos daqui em diante rodam nesse diretório.
Servindo em outra porta
Seção intitulada “Servindo em outra porta”O instalador escreve um .env para https na 443 e não tem parâmetro para outra porta. As duas linhas abaixo no .env movem a instância para outra porta. FLUXER_PUBLIC_PORT define a porta do endereço público, e FLUXER_HTTPS_PORT define a porta do host em que a borda publica o HTTPS:
FLUXER_PUBLIC_PORT=8443FLUXER_HTTPS_PORT=8443docker compose up -dFLUXER_PUBLIC_PORT é a porta do endereço público, e todo endpoint que os serviços anunciam acompanha esse valor. Ele não move o que o host publica, então FLUXER_HTTPS_PORT precisa apontar para a mesma porta. Mova o FLUXER_PUBLIC_SCHEME junto quando a nova porta servir HTTP simples, e defina FLUXER_HTTP_PORT no lugar de FLUXER_HTTPS_PORT. O .env.example fica ao lado do .env e traz as duas receitas completas.
A porta 80 do host continua publicada na receita https e segue respondendo ao desafio ACME. A Let’s Encrypt só se conecta à 80 ou à 443 públicas, então o certificado é emitido se um roteador na frente encaminhar a 80 pública para este host. Sirva seu próprio certificado pelo Caddyfile quando isso não for possível.
Deixe o FLUXER_PUBLIC_ORIGIN comentado, ou mantenha-o coerente com o esquema, o domínio e a porta públicos. Endereços conflitantes podem causar falhas de login e travar a configuração em loop. Veja A origem pública.
Parâmetros do instalador
Seção intitulada “Parâmetros do instalador”| Parâmetro | Significado |
|---|---|
--domain <host> | Hostname em que a instância responde. É perguntado quando ausente |
--email <endereço> | Endereço de contato escrito como FLUXER_VAPID_EMAIL. É perguntado quando ausente |
--dir <caminho> | Diretório de trabalho. Padrão ~/fluxer, ou o diretório atual quando ele já contém uma instância |
--ref <git ref> | Ref de onde vêm os arquivos da stack. Assume a tag da imagem, e main quando a tag é v1 ou latest |
--image-tag <tag> | Tag de imagem que a stack roda. Padrão v1 |
--tls <modo> | bundled ou proxy. Padrão bundled |
--edge-bind <addr:porta> | Bind HTTP simples sob --tls proxy. Padrão 127.0.0.1:8080 |
--non-interactive | Nunca pergunta. Um valor obrigatório ausente vira erro |
--dry-run | Imprime o plano. Não escreve nada e não inicia nada |
--no-start | Escreve tudo e pula o docker compose up -d |
--update | Atualização: registra, faz backup, atualiza os arquivos, baixa, recria e verifica |
--rollback | Restaura as imagens e os arquivos de stack que a execução --update mais recente registrou |
--allow-root | Permite rodar como root |
--engine <comando> | Motor de contêiner a usar. Padrão docker, ou podman quando o docker não existe |
Rode com --dry-run primeiro para ver o que um conjunto de parâmetros faz. O script PowerShell recebe os mesmos parâmetros como -Domain, -Email e assim por diante, e não tem -AllowRoot. Atualização traz os parâmetros que só --update e --rollback leem, e os códigos de saída.
O script é a referência
Seção intitulada “O script é a referência”Leia o instalador de Linux e macOS ou o instalador de Windows, servidos por este site em /install.sh e /install.ps1, antes de executar.
Passo 5: verificar se funcionou
Seção intitulada “Passo 5: verificar se funcionou”Acompanhe a stack se estabilizar:
cd ~/fluxerdocker compose psdocker compose logs -f apiTodo serviço mostra running ou healthy, exceto o seaweedfs-init, que cria os buckets de upload e depois mostra exited (0).
Em seguida, as sondagens públicas. Troque a origem pela sua, com a porta incluída quando a instância responder em uma:
base=https://chat.example.comfor p in /_health /api/_health /gateway/_health /media/_health /.well-known/fluxer /; do printf '%s %s\n' "$(curl -sS -o /dev/null -w '%{http_code}' "$base$p")" "$p"doneNo Windows:
$base = 'https://chat.example.com'foreach ($p in '/_health', '/api/_health', '/gateway/_health', '/media/_health', '/.well-known/fluxer', '/') { '{0} {1}' -f (Invoke-WebRequest "$base$p" -UseBasicParsing).StatusCode, $p}Todos os caminhos retornam 200. O /.well-known/fluxer lista os endpoints que os clientes usam, já com o seu hostname neles.
Passo 6: criar o primeiro administrador
Seção intitulada “Passo 6: criar o primeiro administrador”Abra o hostname no navegador. Uma instância nova não está configurada, então ela serve o assistente de configuração.
Crie uma conta e depois escolha identidade visual, modo de registro, política da comunidade, expiração de mídia, integrações e ajustes de premium. Concluir o assistente fecha o acesso de configuração.
Crie a conta de dono com um endereço de e-mail em um domínio que você controle. O primeiro registro que incluir um endereço de e-mail recebe a ACL curinga de administração, que é acesso total ao painel, a não ser que o registro esteja configurado para reter novas contas para aprovação. Concluir o assistente concede essa mesma ACL à conta que o completou, quando essa conta não tem nenhuma.
Com o e-mail ligado, o endereço passa por uma checagem de DNS antes de a conta existir. O e-mail conta como ligado quando a chave está ativa e o provedor é smtp com uma configuração SMTP completa, então FLUXER_EMAIL_ENABLED=true sozinho não liga a checagem. O domínio do endereço precisa publicar um registro MX, ou um A ou AAAA como alternativa. Um nome que só resolve na sua própria rede, como um .lan, .internal ou home.arpa, não publica nenhum dos dois, e o formulário de conta responde That email domain cannot receive mail. qualquer que seja o endereço. Use um domínio com registros públicos, ou deixe o e-mail desligado.
O .env.example vem com FLUXER_EMAIL_ENABLED=false, o que marca todo endereço como verificado na criação e não envia mensagem alguma. Uma senha de dono esquecida, portanto, não tem redefinição por e-mail. Anote-a, e cadastre uma passkey ou uma segunda conta de administrador antes de abrir o registro.
Depois entre no painel de administração em https://chat.example.com/admin com a conta que tem a ACL curinga. A página Instance Config traz tudo o que o assistente perguntou, mais modo de registro, aprovações e chaves de integração. Limit Config guarda os limites da instância publicados aos clientes. Voice Regions e Voice Servers já vêm preenchidas, então voz não precisa de configuração ali.
O cliente desktop abre o app web hospedado do canal de release dele, então acesse sua própria instância pelo navegador. A issue #1088 do projeto de origem acompanha esse ponto e está em andamento.
Configuração lista todos os ajustes de runtime e a variável de ambiente que sobrescreve cada um.
Backups
Seção intitulada “Backups”A recuperação exige o .env, um dump do banco e um backup de seaweedfs-data, que guarda uploads, avatares, denúncias e coletas de dados. Veja Volumes e buckets para tudo o que precisa de backup.
O dump não custa indisponibilidade, então rode-o de forma agendada com a stack no ar:
cd ~/fluxermkdir -p backupsdocker compose exec -T postgres pg_dump -U fluxer -d fluxer --format=custom \ > "backups/fluxer-$(date -u +%Y%m%dT%H%M%SZ).dump"O PowerShell escreve UTF-16 com >, o que corrompe um dump binário. No Windows, escreva o dump dentro do contêiner e copie para fora:
mkdir -Force backupsdocker compose exec -T postgres pg_dump -U fluxer -d fluxer --format=custom -f /tmp/fluxer.dumpdocker compose cp postgres:/tmp/fluxer.dump backups/fluxer.dumpdocker compose exec -T postgres rm /tmp/fluxer.dumpA cópia dos uploads para a stack, porque uma cópia com o serviço no ar pode pegar um arquivo em meio à escrita. O Compose prefixa os nomes de volume com o nome do projeto, que a stack define como fluxer:
docker compose stopdocker run --rm -v fluxer_seaweedfs-data:/data -v "$PWD/backups:/backup" alpine:3.22 \ tar czf /backup/seaweedfs-data.tgz -C /data .docker compose up -dNo PowerShell, escreva ${PWD} no lugar de $PWD.
Você terminou quando backups contiver um dump e um tarball e todo serviço voltar a mostrar running.
O sh install.sh --update faz os dois backups antes de atualizar. Veja O que o backup cobre para backups agendados e Restaurar um backup para recuperação.
Remover a instância
Seção intitulada “Remover a instância”Derrube a instância e apague os dados dela:
docker compose down -vAtualização
Seção intitulada “Atualização”A tag padrão v1 acompanha a release compatível mais recente. O mesmo script atualiza a instância:
cd ~/fluxersh install.sh --updateO --update registra as imagens em execução, faz backup do banco e dos uploads, atualiza os arquivos da stack, baixa as imagens, recria os contêineres e verifica. Ele não toca em nenhum segredo do .env. No Windows é .\install.ps1 -Update. Rode sh install.sh --update --dry-run primeiro para ver o plano.
Atualização cobre o que o backup guarda, como reverter, como fixar uma release e como recuperar espaço em disco.
Onde pedir ajuda
Seção intitulada “Onde pedir ajuda”Abra issues e acompanhe o desenvolvimento no GitHub.

