Servidor RustDesk próprio: hbbs e hbbr em Docker

O Quick Assist resolve um pedido pontual e o TeamViewer cobra uma licença anual, mas os dois partilham o mesmo defeito de fundo: o tráfego do suporte remoto atravessa servidores de terceiros, e a sessão inteira — ecrã do cliente, passwords escritas em frente ao utilizador, ficheiros copiados — vive nos servidores deles. O RustDesk inverte a equação: o cliente é aberto e o servidor é teu. Duas peças bastam, o hbbs (rendezvous e sinalização, ID Server) e o hbbr (relay), e a versão de código aberto 1.1.16 do servidor corre numa máquina de bolso. Numa PME, isto significa suporte remoto com o mesmo fluxo do TeamViewer — ID de 9 dígitos e palavra-passe de sessão — sem tráfego de sessão a sair da tua infra-estrutura.

Este guia parte de um servidor Linux limpo (Ubuntu ou Debian, físico ou VPS): instala o Docker, sobe os dois serviços com o compose oficial, abre as portas na firewall, confirma a chave de encriptação e liga o primeiro cliente.

Neste artigo

1. Como o RustDesk liga dois computadores

Dois serviços compõem o RustDesk Server OSS: o hbbs faz de ID/rendezvous/signaling server — os clientes registam-se nele, é ele quem entrega ao computador B o pedido de ligação do computador A, e por isso é a peça que o cliente precisa de conhecer obrigatoriamente — e o hbbr é o relay que transporta os túneis de dados (ecrã, teclado, ficheiros) quando a ligação directa falha.

O fluxo de uma sessão:

  1. O computador que pede apoio informa o hbbs do ID de destino (9 dígitos).
  2. O hbbs entrega o pedido ao outro computador (ambos estão registados nele).
  3. Os dois tentam uma ligação directa entre os dois (hole punching em TCP e UDP sobre a porta 21116).
  4. Se a directa falhar (NAT restritivo ou ISP com CGNAT), a sessão segue pelo relay do hbbr.

Quando a ligação directa consegue estabelecer-se, a sessão passa directamente entre os dois computadores e o servidor apenas faz o encontro inicial. O relay entra nos casos em que não é possível: o tráfego aí é contido, de 30 KB/s até uns 3 MB/s num ecrã 1920×1080, e em trabalho de escritório ronda os 100 KB/s. Por isso uma máquina pequena serve: os requisitos de hardware oficiais dizem que a configuração mínima de um cloud server básico chega, inclusive um Raspberry Pi.

Nota

o hbbr existe para o pior caso. Numa rede onde a larga maioria das ligações directas falha, os limites de largura de banda do relay contam, e a secção 7 cobre os seus limites, activos por omissão (128 Mb/s por ligação).

2. Instalar o Docker no servidor

O hbbs e o hbbr correm em containers Docker (a via recomendada na documentação oficial). Num servidor Ubuntu sem Docker, o script de conveniência oficial do Docker Engine prepara tudo:


# servidor Linux (Ubuntu/Debian) — script de conveniência oficial do Docker
bash <(wget -qO- https://get.docker.com)

O Docker fornece o script em get.docker.com oficialmente e a própria documentação de instalação do RustDesk o lista como método recomendado. A própria Docker nota que o script de conveniência não é o caminho recomendado para ambientes de produção — num servidor em produção, os passos por repositório apt da documentação do Docker são a via mais conservadora. Confirmar o Docker e o plugin de compose:


docker --version
docker compose version

Saída num Ubuntu 24.04 com Docker 28:


Docker version 28.3.3, build e2397be
Docker Compose version v2.39.2

Números divergem, o que importa é existirem ambos. O plugin docker compose vem incluído no script de conveniência — nenhum pacote extra é necessário.

3. Sobe hbbs e hbbr com o compose oficial

A própria documentação publica um ficheiro compose pronto — o comando oficial de instalação o descarrega para compose.yml no directório corrente:


mkdir -p ~/rustdesk-server && cd ~/rustdesk-server
wget rustdesk.com/oss.yml -O compose.yml
sudo docker compose up -d

O compose.yml oficial, verbatim da documentação — a diferença para os comandos docker run -td do mesmo guia é só a forma de orquestração (a flag -td pertence ao docker run, não ao compose):


services:
  hbbs:
    container_name: hbbs
    image: rustdesk/rustdesk-server:latest
    command: hbbs
    volumes:
      - ./data:/root
    network_mode: "host"

    depends_on:
      - hbbr
    restart: unless-stopped

  hbbr:
    container_name: hbbr
    image: rustdesk/rustdesk-server:latest
    command: hbbr
    volumes:
      - ./data:/root
    network_mode: "host"
    restart: unless-stopped

Três pormenores importantes no ficheiro:

  • network_mode: "host" — os containers partilham a rede do anfitrião, sem mapeamento de portas (-p). É a variante que a documentação prefere em Linux: o hbbs vê os IPs reais dos clientes em vez do IP interno do Docker (172.17.0.1), que é o que o rendezvous precisa para coordenar ligações entre pares. Fora de Linux, o --net=host não existe, e o guia oficial aconselha removê-lo caso a ligação dê problemas na tua plataforma.
  • ./data:/root — os dois containers partilham o mesmo volume. O hbbs escreve a base de dados de clientes e os ficheiros de chave no directório mapeado, e é aí que tudo o que tem de sobreviver a uma actualização vive.
  • depends_on no hbbs — o hbbr arranca antes, em ordem de criação dos containers — o hbbs depende do hbbr por causa dessa ordem de arranque, e é a única dependência do compose.

Ao fim de alguns segundos, confirmar:


sudo docker compose ps
sudo docker logs hbbs --tail 20

Saída do compose ps com os dois serviços activos:


NAME      IMAGE                              COMMAND   SERVICE   CREATED          STATUS
hbbr      rustdesk/rustdesk-server:latest    "hbbr"    hbbr      12 seconds ago   Up 11 seconds
hbbs      rustdesk/rustdesk-server:latest    "hbbs"    hbbs      12 seconds ago   Up 11 seconds

Nos logs do hbbs procura as linhas de inicialização do servidor e do serviço de sinalização. Avisos isolados no arranque (por exemplo sobre a porta UDP ou a interface de rede escolhida) são normais num arranque saudável — o que importa é os serviços hbbs e hbbr ficarem em execução, visíveis no compose ps.

Nota

a imagem rustdesk/rustdesk-server:latest do Docker Hub corresponde no momento da escrita à versão 1.1.16 (2026-07-20). A instalação fixa a versão com rustdesk/rustdesk-server:1.1.16, para quem prefere actualizar por decisão e não por rede. Ambas as tags apontam ao mesmo digest no Docker Hub (sha256:8ecdab65deb7), confirmado na API de tags.

4. Portas a abrir na firewall

As portas oficiais do RustDesk Server OSS, conforme o guia de instalação:

Porta Protocolo Serviço Função
21115 TCP hbbs Teste de tipo de NAT
21116 TCP hbbs Hole punching e serviço de ligação
21116 UDP hbbs Registo de ID e heartbeat dos clientes
21117 TCP hbbr Serviço de relay
21118 TCP hbbs Web clients (WebSocket)
21119 TCP hbbr Web clients (WebSocket)
21114 TCP — Consola web, exclusiva do RustDesk Server Pro

O web client (usar o RustDesk dentro do browser, em rustdesk.com/web) é o único motivo para abrir as 21118 e 21119. Sem essa via de acesso, o guia oficial manda deixá-las fechadas: as portas WebSocket confiam nos headers X-Real-IP/X-Forwarded-For quando os vê chegar por um proxy inverso, e quem chega directo às 21118/21119 pode falsificar um IP de cliente nos registos. Para o caso mais comum — só aplicações desktop e móveis — a firewall fica com:


# UFW — regras que o próprio guia oficial usa
sudo ufw allow 21115/tcp
sudo ufw allow 21116/tcp
sudo ufw allow 21116/udp
sudo ufw allow 21117/tcp
sudo ufw reload

⚠ Atenção

a 21116 é a única porta que precisa de UDP, e é a que os clientes mais consomem: o heartbeat usa-a. Só TCP na 21116 é uma causa típica de clientes que ligam e desligam sem registo estável.

Nas portas TCP de serviço (ufw allow 21114:21119/tcp), o oficial abre o intervalo inteiro, incluindo a 21118 e a 21119, porque o guia assume que quem as quer fechadas as gere por regra própria. Uma alternativa ainda mais conservadora: fechar tudo por omissão e abrir apenas as 21115, 21116 (TCP+UDP) e 21117 — o servidor corre sem as portas de Consola (21114, apenas Pro) e sem web clients.

À distância, confirmar que a porta 21116 responde em ambos os protocolos a partir da tua máquina de trabalho — são dois serviços independentes no mesmo número:


nc -vz RUSTDESK.EXEMPLO.PT 21116   # deve dar "succeeded" (TCP)
nc -vzu RUSTDESK.EXEMPLO.PT 21116  # deve dar "succeeded" (UDP)

5. Chaves de encriptação e o id_ed25519

O RustDesk encripta as sessões com Ed25519: o hbbs guarda o par de chaves em dois ficheiros no volume dos containers, o id_ed25519 (chave privada) e o id_ed25519.pub (chave pública), e é o conteúdo deste público que vai em cada cliente do parque. O par gera-se na primeira execução do hbbs, e é por isso que o volume ./data:/root importa: se o container for recriado sem volume, nasce um par novo e todos os clientes deixam de confiar no servidor.

Ver o que o primeiro arranque produziu:


ls -l ~/rustdesk-server/data/

-rw-r--r-- 1 root root   12288 Out  1 10:12 db_v2.sqlite3
-rw------- 1 root root      88 Out  1 10:12 id_ed25519
-rw-r--r-- 1 root root      44 Out  1 10:12 id_ed25519.pub

O conteúdo do .pub é a chave a configurar nos clientes:


cat ~/rustdesk-server/data/id_ed25519.pub

OeVuKQ5iPrbA2OvV2QO3zWxQ6OaKJXJl+O0mNf0WJ4y

(é um exemplo, o teu valor é outro)

Regras da chave, conforme a documentação de variáveis e flags:

  • O hbbs arranca por omissão com -k -, que significa “usa o par guardado no directório de trabalho, gera-o se não existir”. É o comportamento do compose oficial, nenhum par é preciso configurar. A documentação usa indiferentemente - ou _ neste valor, com o mesmo efeito.
  • Para impor um par próprio (porque migras de um servidor anterior, por exemplo), coloca os dois ficheiros no directório de trabalho antes do primeiro arranque.
  • Um valor vazio de -k desactiva a validação de chaves — clientes com qualquer chave são aceites. É o default do hbbr, e uma configuração que convém conhecer bem: num servidor público, o hbbr sem chave não rejeita clientes alheios.

6. Ligar o primeiro cliente

No cliente RustDesk (desktop, em qualquer plataforma), é um só ecrã que importa: Definições → Rede → ID/Relay Server, com quatro campos:

Ecrã Rede do cliente RustDesk com os campos ID Server, Relay Server, API Server e Key
Ecrã Rede do cliente RustDesk: ID Server, Relay Server, API Server e Key (imagem oficial da documentação do projecto)
  1. ID Server — o host ou IP do servidor, ex.: rustdesk.exemplo.pt. O :21116 é opcional — sem porta, o cliente usa a 21116 por omissão.
  2. Relay Server — deixa em branco: o RustDesk deriva-o do ID Server (o hbbr na :21117).
  3. API Server — só se usa com o RustDesk Server Pro, o OSS não tem consola web: deixa em branco.
  4. Key — o conteúdo do id_ed25519.pub do teu servidor.

Aplicar e reiniciar o cliente (o RustDesk avisa quando é preciso). Um primeiro teste funcional: no computador de destino, anota o ID de 9 dígitos que aparece no cliente, e no computador de origem pede a ligação com a palavra-passe de sessão do destino. Se a ligação se estabelecer, a instalação funciona de ponta a ponta, e o servidor só participou no rendezvous.

Para distribuição em escala, os métodos comuns são dois: a cópia da configuração de um cliente já configurado (botão de export no mesmo ecrã de Rede) e o --config na linha de comandos com a config-string exportada do cliente (Definições → Rede), na documentação de configuração do cliente.

7. Pós-instalação: relay opcional do hbbr

Duas situações merecem uma visita pós-instalação:

Forçar tudo pelo relay. Em redes em que a ligação directa entre os dois extremos nunca se estabelece (dois CGNAT, por exemplo), o hbbr pode ser a única via útil, e tentativas directas apenas atrasam a sessão. Força o relay com ALWAYS_USE_RELAY=Y no serviço hbbs (é onde a variável vai no exemplo oficial, enquanto as de largura de banda vão no hbbr):


    environment:
      - ALWAYS_USE_RELAY=Y

Limites de largura de banda do relay. Quando o relay é a via, cada ligação consumida no hbbr conta para os limites por omissão de 128 Mb/s por ligação (SINGLE_BANDWIDTH) e 1024 Mb/s no conjunto (TOTAL_BANDWIDTH). São ajustáveis por variáveis de ambiente no container do hbbr, e o guia de variáveis deixa claro que servem para proteger o servidor do consumo de um cliente anómalo, não para racionar utilizadores.

Para servidores com muitos clientes a despejar UDP heartbeats, a doc oficial sugere também subir o limite do sistema de receive buffer UDP (sysctl net.core.rmem_max=52428800, conforme a secção do RMEM).

8. Confirmar o funcionamento

Três testes com o servidor no ar:

  1. Registo — no cliente de destino confirmar que o ID aparece (9 dígitos) e o ponto verde da disponibilidade está activo: se o cliente mostra “pronto”, o rendezvous com o hbbs funciona.
  2. Ligação directa — pedir sessão remota entre os dois computadores e confirmar que a sessão funciona. O modo de ligação em uso também se confirma nos logs do hbbs e do hbbr: a sessão com relay aparece registada no hbbr, a directa termina sem entrar nele.
  3. Log do servidor — docker logs hbbs --tail 50 e (se a sessão passou pelo relay) docker logs hbbr --tail 50. O hbbs e o hbbr registam cada ligação entrante com o IP de origem.

Para inventário de clientes registados, no directório dos dados:


sudo sqlite3 ~/rustdesk-server/data/db_v2.sqlite3 "SELECT * FROM peer;"

Nomes de colunas divergem entre versões de base de dados, e o esquema pode não ter a tabela peer — se o SQLite reclamar, é normal: a base evolui com o servidor, e não existe documentação estável que a descreva.

9. Erros comuns

Erro / sintoma Causa provável Correcção
Cliente regista, a sessão não liga Porta 21116 UDP fechada na firewall Abrir a 21116/UDP (o heartbeat e o registo dependem dela)
Erro de chave no lado do cliente ou sessão falha de imediato A chave do cliente difere da chave pública do hbbs Voltar a copiar o id_ed25519.pub actualizado para os clientes e apagar a antiga
Os clientes deixam de confiar no servidor (chave diferente) O volume ./data:/root nunca foi montado, o par de chaves regenera-se a cada container nascido Recrear o container com volume mapeado e voltar a configurar clientes
Sessão lenta, com atraso e saltos Sessão a passar pelo relay com largura de banda limitada Testar a ligação directa (desactivar ALWAYS_USE_RELAY se activo), rever limites do hbbr
Cliente não liga de todo Firewall/ISP a bloquear a 21116 TCP e UDP Testar com nc -vz e nc -vzu a partir de uma máquina externa

10. Checklist

  • [ ] Docker instalado e o par hbbs/hbbr activo com docker compose ps
  • [ ] Portas 21115, 21116 (TCP+UDP) e 21117 abertas na firewall, 21118/21119 fechadas (sem web client)
  • [ ] ~/rustdesk-server/data/ com o par id_ed25519 / id_ed25519.pub e o SQLite de clientes
  • [ ] ID Server + Key configurados em cada cliente do parque
  • [ ] Backup do directório data/ agendado (é o único estado do servidor)
  • [ ] Teste de sessão remota ponta-a-ponta concluído (directa e pelo relay)

11. Artigos relacionados

12. Fontes oficiais