pular pro conteúdo
~/docs/servidor
Servidor

Servidor dedicado

atualizado 2026-11-029 min de leitura editar esta página

Por padrão quem cria a sala é o servidor (e precisa de túnel/porta aberta). Se você tem uma VPS ou um PC com porta aberta, pode deixar uma sala sempre no ar com o telinha-server: um binário estático de ~400 KB, sem dependências.

Todo mundo entra com Entrar numa sala → ip-da-vps:7777 + senha.

Rodando direto

zig build server            # gera zig-out/bin/telinha-server-{x86_64,aarch64}
./telinha-server-x86_64 --porta 7777 --senha "uma senha boa" --nome "Sala da galera" --admin "token-secreto"

Ou pelas variáveis TELINHA_PORTA, TELINHA_SENHA, TELINHA_NOME, TELINHA_ADMIN.

O --admin é um token: quem entrar com ele (no app: Entrar numa sala → Opções avançadas → token de admin, ou --admin TOKEN na linha de comando) ganha a coroa e pode expulsar gente (clique direito no membro).

Docker

docker build -t telinha-server .
docker run -d --name telinha -v telinha-dados:/data -p 7777:7777/tcp -p 7777:7777/udp \
  -e TELINHA_SENHA="uma senha boa" -e TELINHA_NOME="Sala da galera" -e TELINHA_ADMIN="token-secreto" \
  --restart unless-stopped telinha-server

Ou com docker compose up -d usando o docker-compose.yml: copie o .env.example pra .env e preencha a senha e o token de admin antes (sem eles o compose não sobe). A imagem final é FROM scratch (só o binário), roda sem root e funciona em amd64 e arm64. Mantenha o volume /data: nele ficam a identidade do servidor (servidor.key), o estado da sala e os arquivos; sem ele cada restart cria uma identidade nova e o app de todo mundo avisa que a identidade do servidor mudou.

systemd

/etc/systemd/system/telinha.service:

[Unit]
Description=telinha - servidor de sala
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/telinha-server --porta 7777 --nome "Sala da galera"
Environment=TELINHA_SENHA=uma-senha-boa
Environment=TELINHA_ADMIN=token-secreto
# os logs de depuração que mandarem "pro dono da sala" também ficam aqui
Environment=TELINHA_LOGS=/var/lib/telinha/logs
StateDirectory=telinha
DynamicUser=yes
Restart=on-failure
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes

[Install]
WantedBy=multi-user.target
sudo install -m755 zig-out/bin/telinha-server-x86_64 /usr/local/bin/telinha-server
sudo systemctl enable --now telinha
journalctl -u telinha -f

Atualizar sozinho

Com --atualizar-sozinho (ou TELINHA_ATUALIZAR=1) o servidor confere a release nova a cada 6 h, baixa o telinha-server dela, confere a assinatura e a versão assinada (o mesmo do app), e só reinicia quando a sala fica 2 minutos vazia (bots não contam). Reinicia no mesmo processo, então o systemd e o Docker nem percebem; se a versão nova cair nos primeiros 10 s, a próxima abertura volta pra anterior sozinha.

O executável precisa estar numa pasta em que o serviço pode escrever. Com a unit acima (ProtectSystem=strict), use a pasta de estado:

sudo install -D -m755 zig-out/bin/telinha-server-x86_64 /var/lib/telinha/bin/telinha-server
# e na unit: ExecStart=/var/lib/telinha/bin/telinha-server --atualizar-sozinho ...

Sem poder escrever, o servidor só avisa no log que tem versão nova. No Docker, atualize a imagem (o binário do container é só leitura).

Logs de depuração da galera

No app, Configurações → Depuração → Pro dono da sala manda o log pela própria sala. Ele chega em todo mundo que entrou com o token de admin (vai pra pasta logs-recebidos, do lado da configuração). Com --logs PASTA (ou TELINHA_LOGS), o servidor dedicado também guarda uma cópia: um log mandado com nenhum admin na sala não se perde. Cada pessoa manda um log por minuto, até 8 MB.

Com --coletar-logs (ou TELINHA_COLETAR_LOGS=1) não precisa pedir pra ninguém: quem entra é avisado, o app grava o log enquanto a pessoa está na sala e quem tem a coroa clica com o botão direito na pessoa → Pegar o log. O relatório de travamento de quem caiu chega sozinho. Quem não quiser desliga em Configurações → Depuração (e você fica sabendo que não veio). Sem --logs, os logs ficam em logs, do lado do arquivo de estado.

Quando o servidor cai

Se o servidor cair (um bug) e o systemd o reabrir, ele escreve no chat do canal padrão "O servidor reiniciou depois de uma queda (motivo: …)", com o arquivo e a linha, e deixa o detalhe em ultima-queda.txt, do lado do arquivo de estado (a pilha inteira também vai pro journal).

Canais

Um servidor só pode ter várias salas ao mesmo tempo, como no IRC: cada canal com o seu chat, a sua gente, a sua voz e as suas transmissões, e a galera pula de um pro outro sem reconectar (o painel da direita, ou /join nome no chat). O primeiro canal é o padrão.

telinha-server --canais "geral,jogos,filmes"      # canais fixos; qualquer um cria outros
telinha-server --canais "geral,jogos" --sem-canais-novos   # só esses

(ou TELINHA_CANAIS). Canal que alguém criou some quando esvazia. O convite pode apontar direto pra um canal: telinha://host:7777/jogos#senha.

Admin dos canais, calls e o que sobrevive a reiniciar

Cada canal tem o seu chat; a call (voz e transmissões) é separada: dá pra ler um canal e continuar na call de outro (o fone em cada canal, /call nome, ou o botão da cápsula). Quem entrou com o token de admin clica com o botão direito num canal pra fixar, trancar (só admin entra), pôr senha ou tópico, e numa pessoa pra levar ela pra outro canal. Canais fixos (com senha, trava e tópico), banidos, silenciados e sem pincel vão pra um arquivo de estado (--estado ARQUIVO / TELINHA_ESTADO; por padrão estado.txt do lado da chave) e voltam depois de reiniciar.

Assistir pelo navegador

Quem não tem o app assiste por um link, sem instalar nada. O servidor serve a página e repassa os mesmos quadros que já manda pros apps (quem transmite não gasta nada a mais). O navegador só decodifica vídeo em página https, então a porta web fica em 127.0.0.1 e precisa de um HTTPS na frente:

  • Sem conta, sem domínio: --web 7778 --web-tunel sobe um túnel rápido da Cloudflare (cloudflared, baixe aqui) e divulga o endereço https://….trycloudflare.com na sala; no app, o botão da telinha (ao lado do convite) copia o link com a senha. O endereço muda a cada vez que o túnel sobe — o app sempre recebe o atual.
  • Com domínio seu (túnel nomeado da Cloudflare, Caddy, nginx...): aponte o HTTPS pra http://127.0.0.1:7778 (com WebSocket) e use --web 7778 --web-link https://tela.seudominio.com.

No systemd, junte às opções do ExecStart (ex.: --web 7778 --web-tunel) com o cloudflared em /usr/local/bin.

Bots

Bots (o SDK em Python, o bot de música) entram com a senha da sala e aparecem com a etiqueta BOT; nunca viram admin. Pra decidir quem entra:

  • --sem-bots (TELINHA_SEM_BOTS=1): recusa todos os bots.
  • --so-protocolo-novo (TELINHA_SO_PROTOCOLO_NOVO=1): recusa apps de antes da 3.8 (protocolo 6). No protocolo 6, quem alcança a porta consegue, com uma conexão, algo pra testar a senha da sala offline; ligue quando todo mundo tiver atualizado (o app se atualiza sozinho; os bots precisam do SDK da 3.8 em diante).
  • --token-bots SEGREDO (TELINHA_TOKEN_BOTS): só bot que mandar esse token (Bot(..., bot_token="SEGREDO"), --token-bots no bot de música). Gente comum continua entrando só com a senha.

Arquivos

Quem está na sala manda arquivos (até 256 MB) e cada um baixa quando quiser. O servidor guarda no disco, cifrados com uma chave que só existe na memória dele (reiniciou, o que sobrou é apagado), em --arquivos PASTA / TELINHA_ARQUIVOS (por padrão a pasta arquivos do lado do estado; no systemd acima, /var/lib/telinha/arquivos). Expiram 2 h depois de mandados, no máximo 2 GB no total. Sem uma pasta que dê pra escrever, a sala fica sem arquivos (as imagens no chat continuam).

Identidade do servidor

O servidor guarda uma chave fixa (--chave ARQUIVO / TELINHA_CHAVE; por padrão servidor.key no StateDirectory= do systemd, /var/lib/telinha/servidor.key rodando como root, senão ~/.config/telinha/servidor.key), criada na primeira vez com permissão 0600. A impressão aparece no log ao subir e vai no convite (telinha://host:7777!impressão#senha): o app confere que é mesmo este servidor antes de mandar qualquer coisa. Guarde o arquivo da chave ao reinstalar — chave nova faz quem já entrou ver o aviso "a identidade do servidor mudou".

Estatísticas do servidor

Quem entra com o token de admin (--admin) ganha um botão de medidor no topo da sala: CPU e memória do processo do servidor, banda chegando e saindo, gente por canal, UDP ou TCP, quanto cada um está recebendo, a fila de envio de cada um, e um palpite em português claro de qual é o gargalo (CPU do servidor, upload do servidor, a conexão de uma pessoa). O servidor só mede enquanto alguém está com essa janela aberta.

Firewall e banda

  • Libere a porta escolhida em TCP e UDP (ufw allow 7777). O TCP leva o controle e o chat; o UDP, na mesma porta, leva vídeo, som e voz. Sem o UDP funciona, mas tudo vai pelo TCP (perda de pacote segura o que vem atrás).
  • Na nuvem (Oracle, AWS, GCP...) tem também o firewall da rede, fora da máquina (security list / security group): libere TCP e UDP 7777 lá também.
  • Nas imagens Ubuntu da Oracle, o iptables rejeita tudo antes do UFW; a regra vai antes do REJECT: sudo iptables -I INPUT <linha do REJECT> -p udp --dport 7777 -j ACCEPT (e o mesmo com -p tcp), salvando em /etc/iptables/rules.v4.
  • O servidor só encaminha: quase não usa CPU. A banda de saída é (soma das transmissões) × (espectadores de cada uma). Uma transmissão 1080p "equilibrada" gira em 0,3–6 Mbit/s dependendo do que está na tela.

Se quem cria a sala está atrás de NAT/CGNAT, o próprio telinha abre um túnel (protocolo do bore, servidor bore.pub): no app, Criar link público; no servidor dedicado, --publico:

./telinha-server --publico
# [21:03] link público: bore.pub:41234  —  convite: telinha://bore.pub:41234#k3m9qx2a

Sem --senha, uma senha aleatória é criada (o endereço é público). Se o túnel cair, ele reconecta pedindo a mesma porta, então o convite continua valendo. Outro servidor bore (o seu, por exemplo): --publico meu.servidor.com (ou tunnel_host= no config.ini do app).

Sem VPS: porta aberta no roteador (UPnP)

Com o roteador de casa deixando (a maioria vem com UPnP ligado), dá pra ter conexão direta, sem túnel no meio: menos atraso (o bore.pub fica em outro continente) e sem o limite de banda dele. No app, Abrir porta no roteador; no servidor dedicado, --upnp:

./telinha-server --upnp
# [21:03] porta aberta no roteador: 177.45.10.8:7777  —  convite: telinha://177.45.10.8:7777#k3m9qx2a

A porta fica aberta (renovada a cada 25 min) enquanto a sala está aberta e é fechada quando ela fecha; se o processo cair sem fechar, o roteador apaga sozinho em até 1 h. Se a operadora usa CGNAT (o roteador não tem IP próprio na internet — comum em fibra e 4G), o telinha percebe e avisa: aí o caminho é o link público. O firewall da própria máquina também precisa deixar a porta entrar.

Ou um túnel externo:

túnel comando observação
bore bore local 7777 --to bore.pub grátis, sem conta
ngrok ngrok tcp 7777 TCP exige conta com cartão verificado
serveo ssh -R 0:localhost:7777 serveo.net pode estar instável
playit.gg app do playit grátis, feito pra jogos
Tailscale/ZeroTier/Radmin VPN entre a galera usa o IP da VPN direto

O tráfego é criptografado de ponta a ponta entre cada pessoa e o servidor da sala, então o túnel não vê o conteúdo.