Existe um tipo de contribuição técnica que quase ninguém enxerga, mas que sustenta o acesso à internet
livre de milhares de pessoas todos os dias: doar um pedaço de um servidor para rodar uma bridge da
rede Tor. Diferente de um relé comum, a bridge é um ponto de entrada não listado publicamente, existindo
especificamente para permitir que usuários sob censura alcancem a rede Tor sem que o provedor de internet
local perceba.
Este artigo documenta o processo completo: a fundamentação técnica do que é uma bridge e por que ela
importa, os critérios de escolha da VPS, a implantação da stack em Docker (bridge obfs4, monitoramento e
alertas) e o hardening do host. Ao final, também é discutido o principal ponto de falha encontrado na
prática, a interação entre Docker e UFW, que silenciosamente invalida boa parte das regras de firewall
de uma VPS.
Conceitos
Tipos de nó na rede Tor
A rede Tor é sustentada por voluntários que operam três tipos de nó, com propósitos distintos. O
relé intermediário repassa tráfego já criptografado entre outros nós da rede, sendo público e
listado abertamente no consenso. O relé de saída é o último salto, no qual o tráfego deixa a rede
em direção à internet aberta usando o IP do operador, é o tipo mais necessário, porém o mais sujeito a
reclamações de abuso e a implicações jurídicas. A bridge, por sua vez, é um ponto de entrada
deliberadamente ausente do consenso público.
A distinção é crucial: relés comuns constam de uma lista pública que qualquer governo pode baixar e
bloquear integralmente em uma única operação. A bridge não está nessa lista. Um censor não consegue
bloquear aquilo que não consegue enumerar, e é exatamente aí que reside sua função.
obfs4 e Pluggable Transports
Não basta que o endereço da bridge seja secreto: o tráfego Tor possui uma assinatura reconhecível no
handshake TLS, o que permite que sistemas de Deep Packet Inspection (DPI) identifiquem e bloqueiem
a conexão mesmo sem conhecer o IP de destino. Os Pluggable Transports resolvem esse problema ao
encapsular o tráfego em uma camada de ofuscação.
O obfs4 é o transporte padrão para bridges. Ele aplica um handshake autenticado por uma chave
que só o cliente que possui a bridge line conhece, transformando todo o fluxo em ruído aparentemente
aleatório, sem cabeçalhos fixos, sem padrão de tamanho de pacote reconhecível e sem resposta a sondagens
de quem não possui a chave. Essa última propriedade é o que confere resistência ao active probing:
um censor que se conecte à porta obfs4 sem a chave correta não recebe nada que confirme tratar-se de uma
bridge Tor.
Distribuição e ciclo de vida de uma bridge
Uma bridge recém-criada não é entregue diretamente aos usuários. Ela é registrada junto à
Bridge Authority e passa a ser distribuída pelo Rdsys, o sistema de distribuição do Tor
Project, que a disponibiliza por canais controlados, o BridgeDB via HTTPS, e-mail e Telegram, ou
embarcada no Tor Browser. A distribuição é fragmentada de propósito: nenhum canal entrega o conjunto
completo de bridges, justamente para impedir que um censor enumere todas de uma vez.
Bridges não são permanentes. Países com capacidade de probing ativo em larga escala conseguem
identificar e bloquear bridges ao longo do tempo, mesmo com ofuscação. Isso cria uma dinâmica de reposição
contínua: a rede depende de um fluxo constante de bridges novas, ainda ausentes das listas de bloqueio,
substituindo aquelas que vão sendo queimadas. O valor de uma bridge nova está precisamente nesse ponto.
Relevância operacional
Os números sustentam o argumento. Rússia e Irã são consistentemente os países com maior volume de
conexões via bridge, na casa de dezenas de milhares de usuários diários somados, com picos que se
multiplicam por dezenas de vezes durante períodos de repressão mais intensa. No Irã, conexões diretas ao
Tor estão bloqueadas há anos; para praticamente todo usuário iraniano, a bridge não é uma alternativa -
é o único caminho de entrada existente. A rede opera com algo entre 1.800 e 2.200 bridges ativas em um
dado momento, um número modesto frente à demanda.
Por que não rodar em rede doméstica
A tentação de economizar e rodar a bridge em um computador de casa existe, mas esbarra em limitações
técnicas que uma VPS elimina de imediato.
CGNAT
Boa parte das conexões residenciais, sobretudo móveis e parte das conexões via cabo, opera atrás de
Carrier-Grade NAT, o que significa que o assinante sequer possui um IP público próprio. Sem IP
público, não há como a Bridge Authority alcançar a ORPort para validar a alcançabilidade da bridge. Trata-se
de um impedimento arquitetural, não de configuração.
IP dinâmico
Mesmo sem CGNAT, provedores residenciais rotacionam o IP do assinante periodicamente. Cada troca rompe a
continuidade da bridge, que precisa reconstruir reputação do zero, e os mecanismos de distribuição do
Rdsys favorecem bridges com uptime estável e endereço consistente.
Banda compartilhada
A bridge disputa upload com todo o consumo doméstico: streaming, videochamadas, jogos. Em uma VPS, a banda
é dedicada e previsível.
Termos de serviço
Diversos provedores residenciais proíbem contratualmente a operação de servidores, ainda que não fiscalizem
de forma ativa.
Exposição do IP residencial
Embora a bridge não exponha o operador aos usuários finais, esse é justamente o propósito do desenho -
ela permanece exposta a qualquer sistema de varredura da internet, incluindo os de países que realizam
probing ativo. É preferível que esse endereço seja o de uma VPS descartável, e não o da residência do
operador.
Escolha da VPS
Os requisitos oficiais do Tor Project para uma bridge são modestos: banda mínima de 1 Mbit/s (com faixa
ideal entre 10 e 16 Mbit/s), tráfego mensal mínimo de 100 GB, recomendando-se 2 TB ou mais, e nenhuma
exigência relevante de CPU ou RAM. Isso viabiliza planos de entrada de baixo custo.
Hetzner (CX22)
2 vCPU, 4 GB de RAM, 40 GB NVMe e 20 TB de tráfego mensal, na faixa de R$ 23 a 27/mês. É a melhor relação
entre banda incluída e preço entre os provedores tradicionais.
OVHcloud (linha de entrada)
2 GB de RAM com banda não medida, na faixa de R$ 21 a 25/mês. A ausência de franquia de tráfego elimina
qualquer preocupação com crescimento de uso.
Contabo (Cloud VPS)
4 vCPU, 8 GB de RAM e 100 GB de SSD por aproximadamente R$ 27/mês em contratos promocionais de longo prazo.
Recursos generosos, com desempenho de rede historicamente mais irregular.
BuyVM
Banda não medida a 1 Gbps na faixa de R$ 18/mês. Provedor menor, porém tradicionalmente tolerante a
infraestrutura de privacidade.
O fator decisivo na escolha não é CPU nem RAM, e sim banda alta ou não medida. Uma bridge saudável
e bem distribuída tende a receber tráfego crescente conforme ganha reputação na rede, de modo que um plano
com franquia limitada tende a se tornar gargalo antes do que se imagina. Também é prudente verificar a
política do provedor quanto a nós Tor: bridges e relés intermediários são amplamente aceitos, enquanto
relés de saída costumam ser proibidos.
Consumo real de recursos
Após meses de operação, o consumo medido da stack completa, bridge obfs4, monitoramento via Uptime Kuma e o script de resumo diário, ficou consideravelmente abaixo do que qualquer plano de entrada oferece:
RAM 150-400 MB no total, contra 4-8 GB disponíveis
Disco 1-2 GB para a stack completa, com crescimento lento via logs
CPU média bem abaixo de um núcleo, com picos raros sob tráfego intenso
Na prática, mesmo o plano mais barato da lista anterior mantém folga expressiva de recursos, o que permite que a mesma VPS acumule outras funções, ferramentas de bug bounty e reconhecimento contínuo, por exemplo - sem conflito perceptível com a bridge.
Arquitetura da stack
A stack roda inteiramente em Docker e é composta por três serviços, sobre um host previamente endurecido:
Camada de serviço: obfs4-bridge, construída a partir da imagem oficial do Tor Project
Camada de observabilidade: uptime-kuma, monitorando a porta e alertando via Telegram
Camada de relatório: tor-bridge-report.sh, consultando a API Onionoo do Tor Metrics
Camada de host: UFW, ufw-docker, Fail2Ban, unattended-upgrades e hardening de kernel via sysctl
Hands-on
Preparação do host
Com a instância provisionada, atualize o sistema e instale as dependências básicas.
apt update && apt upgrade -y
apt install -y ufw fail2ban unattended-upgrades curl jq
Em seguida, instale o Docker Engine a partir do script oficial e habilite o serviço.
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
Hardening de kernel
Antes de expor qualquer serviço, aplique as proteções de rede no nível do kernel. Crie o arquivo
/etc/sysctl.d/99-hardening.conf com o conteúdo abaixo.
# Proteções de rede
net.ipv4.conf.all.accept_redirects = 0 # Bloqueia ICMP redirects
net.ipv4.conf.all.send_redirects = 0 # Não envia redirects
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.rp_filter = 1 # Previne IP spoofing
net.ipv4.tcp_syncookies = 1 # Mitiga SYN flood
net.ipv4.conf.all.log_martians = 1
# Proteções de kernel
kernel.kptr_restrict = 2 # Oculta ponteiros de kernel
kernel.dmesg_restrict = 1
sysctl --system
Firewall e o problema do Docker
Configure o UFW com política restritiva, liberando apenas o SSH. As portas da bridge não devem
ser liberadas aqui, o motivo é explicado logo em seguida.
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw --force enable
O ponto crítico: o Docker ignora o UFW por padrão. A razão é a ordem de avaliação do iptables:
o tráfego de uma porta publicada sofre DNAT na cadeia PREROUTING (tabela nat) e é entregue
ao contêiner atravessando a cadeia FORWARD, nunca a cadeia INPUT, que é justamente onde o
UFW aplica suas regras. Ao publicar uma porta em um docker-compose.yml, o Docker ainda insere suas
próprias regras na cadeia DOCKER, avaliada dentro do FORWARD antes de qualquer política do UFW. O
resultado é que um contêiner com porta publicada fica acessível externamente mesmo com o UFW configurado
para negar tudo, e, de forma inversa, tentativas de liberar a porta apenas pelo UFW não surtem o efeito
esperado. É uma divergência silenciosa entre o que o ufw status reporta e o que o kernel
efetivamente aplica.
A correção é o projeto comunitário ufw-docker, que reorganiza as cadeias de forma que o UFW volte a
governar o tráfego destinado aos contêineres.
wget -O /usr/local/bin/ufw-docker \
https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
chmod +x /usr/local/bin/ufw-docker
ufw-docker install && systemctl restart ufw
A partir desse ponto, a liberação passa a ser feita por contêiner, e não por porta genérica. As
regras específicas da bridge são aplicadas após a subida dos serviços.
* A validação precisa ser feita a partir de fora do host, com ferramentas independentes (nmap ou
verificadores de porta online). Confiar apenas no que roda localmente é exatamente o que mascara esse
tipo de falha.
Configuração da bridge obfs4
A imagem oficial do Tor Project encapsula o tor e o obfs4proxy já configurados como
bridge. Crie o diretório do projeto e o arquivo de variáveis de ambiente.
mkdir -p /opt/tor-bridge && cd /opt/tor-bridge
# .env
OR_PORT=443
PT_PORT=8443
EMAIL=seu-email@exemplo.com
NICKNAME=SuaBridge
A escolha das portas não é arbitrária. A ORPort é usada para a comunicação com a rede Tor e para a verificação de alcançabilidade pela Bridge Authority; a PT_PORT é a porta obfs4 à qual os clientes censurados se conectam. Portas comuns como 443 tendem a atravessar firewalls restritivos com mais facilidade do que portas altas arbitrárias. O EMAIL é usado pelo Tor Project para notificar o operador sobre problemas com a bridge, e o NICKNAME é o identificador público do nó.
Em seguida, defina o docker-compose.yml com os três serviços da stack.
services:
obfs4-bridge:
image: thetorproject/obfs4-bridge:latest
container_name: obfs4-bridge
restart: unless-stopped
env_file: .env
ports:
- "443:443"
- "8443:8443"
volumes:
- tor-data:/var/lib/tor
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: unless-stopped
ports:
- "127.0.0.1:3001:3001"
volumes:
- kuma-data:/app/data
volumes:
tor-data:
kuma-data:
O volume tor-data é o elemento mais importante da configuração: é nele que residem as chaves de identidade da bridge. Perder esse volume significa perder o fingerprint, toda a reputação acumulada na rede e a continuidade da distribuição pelo Rdsys, a bridge volta a ser tratada como um nó novo. O Uptime Kuma, por sua vez, é publicado apenas em 127.0.0.1, deliberadamente inacessível de fora e alcançável somente por túnel SSH.
Suba a stack e acompanhe a inicialização.
docker compose up -d
docker logs -f obfs4-bridge
Agora aplique as regras de firewall por contêiner. Sem esta etapa, a ORPort não é alcançável de fora e a bridge nunca conclui a validação.
ufw-docker allow obfs4-bridge 443/tcp
ufw-docker allow obfs4-bridge 8443/tcp
Validação da bridge
A confirmação definitiva vem dos próprios logs do tor. A mensagem abaixo indica que a Bridge
Authority conseguiu alcançar a ORPort a partir da internet.
docker logs obfs4-bridge | grep -i "self-testing"
[notice] Self-testing indicates your ORPort 203.0.113.10:443 is reachable
from the outside. Excellent. Publishing server descriptor.
Com a bridge publicada, obtenha a bridge line, a string que um cliente censurado utiliza para se conectar manualmente ao nó.
docker exec obfs4-bridge get-bridge-line
obfs4 203.0.113.10:8443 A1B2C3D4E5F60718293A4B5C6D7E8F9012345678 \
cert=Bvg/itxeL4TWKLP6N1MaQzSOC6tBjZmJ3EXAMPLEcert iat-mode=0
* A bridge line não deve ser divulgada publicamente. A distribuição é responsabilidade do Rdsys, que a entrega de forma fragmentada a usuários reais. Publicá-la em um repositório, fórum ou rede social é o caminho mais rápido para que ela seja coletada e adicionada às listas de bloqueio.
Consulta ao Onionoo
A API pública Onionoo expõe os metadados de nós da rede mantidos pelo Tor Metrics. No caso de
bridges, a consulta não é feita pelo fingerprint direto, e sim pelo seu hash SHA-1, mais uma
camada de proteção contra enumeração. Extraia o fingerprint do volume e derive o hash.
docker exec obfs4-bridge cat /var/lib/tor/fingerprint
echo -n "<FINGERPRINT>" | xxd -r -p | sha1sum | cut -d' ' -f1 | tr 'a-z' 'A-Z'
Com o hash em mãos, consulte o estado da bridge.
curl -s "https://onionoo.torproject.org/details?lookup=<HASHED_FINGERPRINT>" | jq
* Bridges recém-criadas levam algumas horas para aparecer no Onionoo e alguns dias até serem efetivamente distribuídas pelo Rdsys. Ausência de retorno nas primeiras horas é comportamento esperado, não sintoma de erro.
Monitoramento e alertas
Como o Uptime Kuma está publicado apenas em loopback, o acesso à interface se dá por túnel SSH,
evitando expor o painel à internet.
ssh -N -L 3001:localhost:3001 root@<IP_PUBLICO>
# Então, localmente:
# http://localhost:3001
No painel, configure um monitor do tipo TCP Port apontando para a PT_PORT (8443) e um segundo para a ORPort (443), com intervalo de 60 segundos. Em seguida, adicione uma notificação do tipo Telegram, informando o token do bot e o chat ID. A queda de qualquer uma das portas passa a gerar alerta imediato - e, para uma bridge, downtime prolongado significa perda de posição na distribuição do Rdsys.
Resumo diário automatizado
Complementando o alerta reativo do Uptime Kuma, um relatório diário fornece a visão de estado da
bridge na perspectiva da própria rede: flags atribuídas, banda observada e data do último descritor
publicado. Crie o script /opt/tor-bridge/tor-bridge-report.sh.
#!/usr/bin/env bash
set -euo pipefail
HASHED_FP="<HASHED_FINGERPRINT>"
BOT_TOKEN="<TELEGRAM_BOT_TOKEN>"
CHAT_ID="<TELEGRAM_CHAT_ID>"
DATA=$(curl -s "https://onionoo.torproject.org/details?lookup=${HASHED_FP}")
RUNNING=$(echo "$DATA" | jq -r '.bridges[0].running')
NICKNAME=$(echo "$DATA" | jq -r '.bridges[0].nickname')
FLAGS=$(echo "$DATA" | jq -r '.bridges[0].flags | join(", ")')
SEEN=$(echo "$DATA" | jq -r '.bridges[0].last_seen')
[ "$RUNNING" = "true" ] && STATUS="online" || STATUS="OFFLINE"
MSG="Bridge ${NICKNAME}
Status: ${STATUS}
Flags: ${FLAGS}
Último descritor: ${SEEN}"
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d "chat_id=${CHAT_ID}" \
--data-urlencode "text=${MSG}" > /dev/null
Torne o script executável e agende a execução diária via cron.
chmod +x /opt/tor-bridge/tor-bridge-report.sh
# crontab -e
0 9 * * * /opt/tor-bridge/tor-bridge-report.sh
* O script contém credenciais do bot do Telegram. Restrinja as permissões com chmod 700 e mantenha-o fora de qualquer repositório versionado.
Fail2Ban e atualizações automáticas
Por fim, complete o hardening do host habilitando o Fail2Ban para o SSH e as atualizações automáticas
de segurança. Uma bridge é um serviço de longa duração e baixa manutenção, justamente o perfil de
máquina que tende a acumular pacotes desatualizados.
systemctl enable --now fail2ban
dpkg-reconfigure --priority=low unattended-upgrades
Considerações finais
O custo total de manutenção de uma bridge fica na faixa de R$ 20 a 30 por mês, e o conhecimento
técnico exigido não ultrapassa o de qualquer pessoa já familiarizada com Linux e Docker. Do ponto de vista
operacional, a única disciplina realmente necessária é preservar o volume de dados do contêiner e manter o
uptime estável.
A lição mais transferível do processo, contudo, extrapola o contexto do Tor: a divergência entre o que o
ufw status reporta e o que o kernel efetivamente aplica sob Docker afeta qualquer serviço
containerizado publicado em uma VPS. Validar a superfície de exposição a partir de fora do host, com
ferramentas independentes, deveria ser etapa padrão de qualquer implantação, e não apenas o desfecho de
uma sessão de depuração.