Blog /
Meu site caiu, e a culpa foi dos meus vizinhos
Não era a primeira vez. Umas semanas atrás eu tinha notado o site fora do ar numa manhã, sem acesso via SSH — mas as luzes de TX/RX piscando normalmente. Reiniciei pela tomada, tudo voltou ao normal, e por precaução ativei a persistência de logs no homelab. Deixei como estava e segui a vida.
Daí, um dia antes de eu começar a escrever este post, o Raspberry Pi que hospeda este site caiu de novo do nada. O site devolveu um 502, o SSH travou, e eu fiz o que normalmente é minha primeira tentativa de solução rápida: tirei da tomada, esperando que ele voltasse. Voltou — mas a instabilidade continuava, e após alguns minutos resolvi acessar o Pi remotamente.
Estava lento: digitar no SSH tinha um delay perceptível, enquanto o htop mostrava tudo normal. As aplicações no cluster ficavam entrando em crash loop, e meu serviço de VPN não parava de apitar. Isso me deixou encucado a ponto de eu ir atrás da causa.
Primeiro: ele nunca travou de verdade
Antes de caçar uma causa, vale descartar as dramáticas. O Pi é um Pi 4B de 4 GB rodando k3s, e os suspeitos óbvios nesse hardware são energia e calor.
$ vcgencmd get_throttled
throttled=0x00x0 significa sem subtensão, sem throttling térmico — nem agora, nem uma única vez desde o boot (o firmware acende o bit 16 se algum dia acontecer). Temperatura do core: 38 °C. O journalctl tinha logado continuamente até o instante em que cortei a energia, e o boot seguinte começou seis segundos depois.
Ou seja, o sistema operacional esteve vivo o tempo todo. Load average 0,4. 1,2 GB de RAM livre. Sem OOM killer, sem kernel panic, sem EXT4-fs error, sem erro de I/O no mmc0. O pod do próprio site, quando finalmente entrei, usava 1 milicore de CPU e 5 MiB de RAM e respondia em menos de 10 ms de dentro do cluster.
Fosse o que fosse, o problema não era o Pi estar lento. Parecia, mas na verdade ele estava ocioso.
O primeiro caminho errado: “é o Tailscale”
Os logs que estavam gritando vinham do tailscaled:
tailscaled: dns udp query: waiting for response or error from [MY_HOST]: context deadline exceeded
tailscaled: health(warnable=no-derp-connection): error: could not connect to the 'Ashburn' relay server
tailscaled: netcheck: UDP is blocked, trying HTTPSE do cloudflared, que é o que de fato expõe o site:
cloudflared: ERR edge discovery: error looking up Cloudflare edge IPs: the DNS query failed
error="lookup _v2-origintunneld._tcp.argotunnel.com on 10.43.0.10:53: server misbehaving"
cloudflared: Initiating shutdownO 10.43.0.10 é o CoreDNS, o serviço de DNS interno do cluster: é ele que traduz nomes em endereços para tudo que roda nele. Só que o CoreDNS não resolve nomes externos sozinho — ele repassa essas consultas para o resolver configurado no /etc/resolv.conf do node. Esse arquivo aponta para o MagicDNS do Tailscale (100.100.100.100) e nada mais. Sem outras alternativas. Na prática, qualquer serviço no cluster que precisasse encontrar um endereço na internet dependia de um único host DNS: um ponto único de falha.
Isso explica o efeito dominó: a conexão do Tailscale oscila → o MagicDNS para de responder → o CoreDNS devolve erro (SERVFAIL) → o cloudflared não consegue localizar os servidores da Cloudflare → o container do túnel encerra e entra em CrashLoopBackOff → o site cai. E o SSH morria junto, porque é pelo Tailscale que eu chego na máquina.
O conserto óbvio era parar de apostar o DNS do cluster inteiro num único resolver. Adicionei um ConfigMap coredns-custom para que os domínios de control-plane do túnel resolvam direto em resolvers públicos, independentes do Tailscale:
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns-custom
namespace: kube-system
data:
cloudflare-tunnel.server: |
argotunnel.com {
forward . 1.1.1.1 1.0.0.1 8.8.8.8
cache 30
errors
}
cloudflare.com {
forward . 1.1.1.1 1.0.0.1 8.8.8.8
cache 30
errors
}É uma mudança boa. Tratou um sintoma mas os túneis continuaram caindo.
E a página de status da Tailscale não registrava nenhum incidente naquele dia. O que significava que o Tailscale também não era a doença — era só o paciente mais barulhento da enfermaria.
Monitorando o Ar de Casa
Parei de ler logs e comecei a medir. Construí um script simples em Bash que rodava no meu notebook e, a cada 45 segundos, tentava entrar no Pi por SSH. Quando conseguia, lia a intensidade do sinal e o contador de retransmissões em /proc/net/wireless, o arquivo onde o Linux expõe a qualidade do enlace Wi-Fi. Quando não conseguia, registrava a queda e quanto tempo ela durava.
O script pegou uma queda ao vivo. Por cerca de dois minutos o homelab ficou completamente inacessível — sem SSH, sem ping, ARP sem resposta. Nessa mesma janela, de outra máquina na mesma rede, o roteador respondia aos meus pings em 1,4 ms com zero perda.
Esse foi o ponto de virada. Não era a operadora. Não era o roteador. O próprio enlace do Pi com a rede caía, sozinho, a cada poucos minutos, e se recuperava antes de eu conseguir um shell.
O homelab é conectado via Wi-Fi. Ele até tem uma porta Ethernet, mas não dá para passar um cabo até onde ele fica.
Ruído extra no caminho
Enquanto eu procurava a raiz do problema, alguns efeitos colaterais deixaram o quadro mais confuso do que precisava:
- O túnel reiniciando sem parar. O
cloudflared, que expõe o site, entrou em crash-loop: 24, depois 28, depois 32 reinícios. Cada reinício grava logs, baixa a configuração de novo e refaz o registro na Cloudflare. Tudo isso é escrita em disco, e o disco aqui é um cartão microSD, que é lento. - A própria investigação. Cada comando que eu rodava para entender o problema (
kubectl logs,journalctl, inspeção de imagens) lia e escrevia no mesmo cartão. Eu estava aumentando a carga que tentava medir.
O resultado foi um aumento real no uso de disco, que dava a impressão de que “o Pi está lento”. Por um tempo tratei aquilo como falta de recurso.
Toda vez que eu de fato media o backend — CPU, memória, latência de request dentro do cluster — ele estava ocioso e respondia na hora. O uso de disco era consequência das coisas falhando e de eu ficar mexendo. Vale lembrar: quando um sistema está instável, boa parte do que você observa é ruído, não a falha em si.
Descendo até a camada física
Com o problema isolado no trecho entre o Pi e o roteador, fui investigar o Wi-Fi em si, uma hipótese de cada vez.
Economia de energia do Wi-Fi. Por padrão, a placa de rede do Pi desliga o rádio por instantes para poupar energia, o que pode causar pequenas interrupções. O log do kernel confirmava que o recurso estava ativo (brcmf_cfg80211_set_power_mgmt: power save enabled). Desliguei:
nmcli connection modify <conn> 802-11-wireless.powersave 2Ajudou um pouco, mas as quedas continuaram.
Uma câmera USB. Na noite anterior eu tinha plugado uma webcam USB 2.0 para um experimento com o ustreamer, sem relação com o site, e ela ficou encostada na antena interna do Pi 4. Dispositivos USB 2.0 e seus cabos são uma fonte bem documentada de interferência em 2.4 GHz, a mesma faixa do Wi-Fi. Desconectei, e a taxa de retransmissão caiu cerca de 4×: o Pi precisava repetir bem menos pacotes para ser ouvido. A intensidade do sinal não mudou, porque ela depende da distância até o roteador; o que diminuiu foi o ruído em volta.
Mesmo assim, continuava caindo.
A varredura das redes vizinhas. Foi aqui que ficou claro. Pedi ao Pi para listar todas as redes Wi-Fi que ele enxergava de onde está:
SSID CANAL SINAL
Copa1002 10 84
Laura 802 2.4G 6 74
DICK 11 70
MEU_HOTSPOT 1 56 <- meu
#CLARO-WIFI 4 50
Four-M 5 50
EVA 4 49
#CLARO-WIFI 4 47
Zizi 3 42
... 30+ redes no totalMeu próprio ponto de acesso, com sinal 56 (numa escala de 0 a 100), chegava mais fraco que o de três vizinhos. E havia um grupo de redes — dois hotspots públicos da Claro(provedora de internet brasileira), “Four-M”, “Zizi” — nos canais 3, 4 e 5, vazando direto para o canal 1, onde o Pi estava.
E a rede de 5 GHz do mesmo roteador, que costuma ser menos disputada? O Pi nem a enxergava. O sinal de 5 GHz alcança menos e atravessa pior as paredes, e de onde o Pi fica essa faixa não chega. A antena do Pi 4B também não ajuda: é pequena, embutida na placa, e tem alcance bem menor que o de um adaptador dedicado — uma reclamação recorrente na comunidade.
Como um canal fica lotado
Colisões de pacotes e protocolos de acesso múltiplo são temas que todo engenheiro de software aprendeu com o Kurose e Ross nas cadeiras de Redes de Computadores na faculdade.
Muita gente faz a disciplina e despreza essas matérias por “nunca vou usar isso no dia a dia” — mas foi uma base teórica importantíssima para eu conseguir analisar e interpretar esse cenário problemático. Resolvi trazer essa explicação aqui para quem não está por dentro.
Um canal de Wi-Fi é uma sala onde uma pessoa fala por vez. Imagine 20 pessoas nessa sala: só uma pode falar por vez, e as outras precisam ficar em silêncio para ouvir. É o que se chama de half-duplex. O protocolo que organiza essa fila é o CSMA/CA, e funciona assim:
- Antes de transmitir, o dispositivo escuta. Se o canal está ocupado, espera.
- Quando o canal fica livre, o dispositivo não transmite na hora — ele conta primeiro um número aleatório de slots de tempo (a “janela de contenção”, ou backoff). A aleatoriedade existe justamente para que dois dispositivos que estavam ambos esperando não pulem no mesmo instante.
- Ele manda um quadro e espera um ACK. Sem ACK → assume que o quadro colidiu ou se perdeu → dobra a janela de contenção → tenta de novo.
Agora escale o número de dispositivos na sala.
Com 2 dispositivos, esse backoff aleatório quase sempre os coloca em slots diferentes. Eles se revezam de forma limpa. Você perde um pouco de tempo de ar na espera (tempo de ar é o tempo de uso do canal, o recurso que todo mundo ali divide), nada mais.
Com 20 dispositivos todos com algo a enviar, a probabilidade de dois deles escolherem o mesmo slot e transmitirem juntos deixa de ser desprezível. Toda vez que isso acontece, é uma colisão: os dois quadros são destruídos, os dois transmissores não recebem ACK, os dois esperam de novo e retransmitem — e essas retransmissões são agora tráfego extra disputando os mesmos slots, tornando a próxima colisão mais provável. Mais carga produz mais colisões produz mais retransmissões produz mais carga. Passado um certo tamanho de multidão, adicionar tráfego faz a vazão útil total do canal cair, não subir.
Então, quão lotada está a minha sala? Meu ponto de acesso mais os poucos clientes dele são talvez 4 rádios. O prédio à minha volta mostra 30+ pontos de acesso, cada um com seus próprios celulares, TVs, câmeras e notebooks — digamos de 60 a 100 rádios ao alcance. E em 2.4 GHz existem só três canais que não se sobrepõem (1, 6, 11). Todo esse tráfego é afunilado em três pistas: cerca de 20–30 dispositivos disputando cada pista, todos se revezando na mesma sala, todos esperando a vez uns dos outros.
O contador de retransmissão que eu ficava olhando era exatamente essa probabilidade tornada visível. Não era um vizinho barulhento: eram dezenas de vizinhos comuns. Pura aritmética.
Duas coisas pioram além do que a aritmética sugere:
- Nós escondidos. O CSMA/CA depende de todo dispositivo conseguir ouvir todo outro dispositivo. Num prédio cheio de paredes, o dispositivo A e o dispositivo C muitas vezes não se ouvem, mas os dois alcançam o ponto de acesso. Nenhum dos dois cede a vez ao outro — não têm como saber que existe alguém para ceder — então transmitem um por cima do outro no AP. Para cada par assim, “escuta antes de falar” simplesmente não funciona.
- Sobreposição de canais. Que é a próxima seção, e o motivo de um vizinho “em outro canal” ainda estar na sua sala.
Por que um “canal diferente” ainda colide
Um canal de Wi-Fi em 2.4 GHz tem 20 MHz de largura, mas os números dos canais estão só 5 MHz um do outro. O canal 1 é centrado em 2412 MHz e ocupa mais ou menos 2402–2422 MHz. O canal 3 é centrado em 2422 — o sinal dele vai de ~2412 a ~2432. Ele cobre metade do canal 1. Só os canais 1, 6 e 11 estão longe o suficiente para não se sobrepor. Três canais utilizáveis, para um prédio inteiro — é por isso que só existem três pistas.
Estar no mesmo canal, na verdade, não é o pior caso — dois pontos de acesso no canal 1 conseguem decodificar um ao outro, então “escuta antes de falar” funciona e eles se revezam. Lento, mas ordenado.
Canais sobrepostos são o caso ruim, porque ali ninguém consegue se revezar: o meu rádio não entende o do vizinho, então não sabe que deveria esperar. Sintonizado no canal 1, ele não consegue decodificar uma transmissão do canal 3 — para ele, aquilo é só ruído em volta. No detalhe: o teste de “o canal está ocupado?” tem duas partes. A primeira é reconhecer o início de uma transmissão Wi-Fi válida (o preâmbulo), e ela falha, porque o rádio não decodifica o canal 3. A segunda é medir a energia bruta no ar, mas o limiar é mais alto, e um vizinho de força média não chega a disparar. Então o meu Pi acha que o ar está livre, transmite, e a energia sobreposta do vizinho corrompe o quadro assim mesmo. Sem ACK, retransmite, repete. O “escuta antes de falar” não tem como ceder a vez a um sinal que ele não reconhece como Wi-Fi.
Esse é o “conflito entre redes que eu não controlo”. Não existe ajuste do meu lado que conserte o roteador de um vizinho no canal 3 — ele só torna a minha sala já lotada ainda mais lotada, com dispositivos com quem eu nem consigo me revezar.
O conserto de verdade: o roteador ainda falava 802.11b
Aqui está a parte que eu não vi chegando — e a que fez a tarde inteira fazer sentido. Meses atrás, a operadora fez uma manutenção na região que deixou meu modem fora do ar por um tempo. Quando voltou, ele tinha sido resetado de fábrica. Entrei só para reativar o rádio de 5 GHz e não conferi mais nada. Nas configurações avançadas de 2.4 GHz, o Modo de Operação tinha voltado para 802.11b — e ficou lá, sem eu notar, desde então.
Em todos esses meses o site nunca tinha caído por causa disso, porque o canal ainda tinha fôlego. O que mudou não foi o roteador: foi o prédio. Toda semana surgem pontos de Wi-Fi novos ao meu redor, e foi essa densidade crescendo que, nas últimas semanas, finalmente passou do limite.
O 802.11b é o padrão original, de 1999: lento, e ainda obriga todo mundo em volta a ir mais devagar. Ele trava em 11 Mbit/s e não tem nenhuma das técnicas que deixam o Wi-Fi moderno rápido (OFDM, MIMO, agregação de quadros, block-ACK). Todo quadro é precedido por um preâmbulo de 192 µs enviado a 1 Mbit/s, uma espécie de aviso lento antes de cada mensagem. E quando um dispositivo só-b está no canal, todo dispositivo mais rápido precisa mandar antes um pedido de licença, também lento (o handshake de proteção RTS/CTS), para o rádio b não transmitir por cima.
Então o meu Pi — que suporta 802.11n tranquilamente — estava preso a 11 Mbit/s, com a maior parte do tempo de ar indo para preâmbulos e overhead de proteção, num canal já corrompido pelos vizinhos. A vazão real era uns 2 Mbit/s, e desmoronava com qualquer perda.
Isso também piora todos os pontos da seção anterior: quadros mais lentos ocupam a sala por mais tempo, então cada transmissão bloqueia mais candidatos a transmissor, então a probabilidade de colisão para todo mundo sobe. Um ponto de acesso 802.11b numa banda lotada não é só lento para os próprios clientes — é um imposto sobre o canal inteiro.
Mudei o modo para 802.11n (b/g/n). Medi antes e depois:
| 802.11b | 802.11n | |
|---|---|---|
| Taxa negociada | 11 Mbit/s | 130 Mbit/s |
| Retransmissões | 15–50 / min | ~1–6 / min |
| Pi ↔ internet, entre as janelas de interferência | ~2 Mbit/s | ~15 Mbit/s |
Cerca de 7× mais folga no trecho entre o Pi e a internet lá fora. O cloudflared parou de derrubar as quatro conexões QUIC a cada oscilação — os logs dele estavam cheios de:
WRN Serve tunnel error error="failed to accept QUIC stream: timeout: no recent network activity"
WRN Failed to dial a quic connection error="failed to dial to edge with quic: timeout: no recent network activity"
INF Retrying connection in up to 8sEssa cascata — todas as conexões expirando por inatividade ao mesmo tempo e depois tentando reconectar com esperas cada vez maiores — era o mecanismo por trás dos relatos de “a página leva 40 segundos para carregar”. Com OFDM e agregação fazendo o mesmo trabalho numa fração do tempo de ar, uma interferência breve deixou de ser suficiente para derrubar o túnel.
O que ainda está quebrado
O 802.11n trouxe de volta estabilidade e velocidade. Não trouxe imunidade.
Rodei o mesmo script por 30 minutos depois da mudança e ele ainda pegou quedas — a maioria curta, mas um blackout completo de 4,5 minutos. As colisões de canal adjacente continuam ali, porque nunca foram minhas para consertar. Num trecho bom o enlace agora está genuinamente ok; quando um vizinho começa a mover tráfego de verdade no canal 3, o meu canal 1 ainda sofre.
As soluções definitivas são as que não envolvem o ar:
- Adaptadores Powerline (PLC) — um no roteador, um na
eth0do Pi. Confiabilidade de cabo sobre a fiação elétrica que já existe na casa, sem passar cabo. - Aproximar o Pi do alcance de 5 GHz do roteador — essa banda está quase vazia aqui.
Os dois estão na lista. Enquanto isso, o site está no ar, rápido entre as janelas de interferência, e eu entendo exatamente por que ele faz o que faz.
No fim, o que mais me marcou foi a coincidência. Moro num prédio comercial onde surgem pontos de Wi-Fi novos toda semana. Um reset de modem forçado por uma manutenção da operadora deixou um protocolo de 1999 ligado sem eu notar. Uma webcam USB pousada do lado errado da antena. A distância até o roteador. Nenhum desses eventos tem relação um com o outro — e juntos formaram uma espécie de coincidência poética que derrubou o site. Fico feliz de ter aprendido algo com tudo isso.
Aprendizados
- O erro mais barulhento raramente é a causa raiz. O
tailscaledgerou 90% do volume de log e 0% da falha. Ele foi o primeiro componente a perceber que a rede sumiu, não o motivo de ela ter sumido. - Descarte as camadas de cima para baixo. Energia, depois temperatura, depois CPU/memória, depois a aplicação, depois a rede, depois — por último — o enlace físico. Eu teria economizado horas indo nessa ordem em vez de perseguir os logs mais barulhentos.
- Um sistema instável mostra, na maior parte, ruído. O uso de disco, os crash-loops, os contadores de reinício — tudo real, tudo consequência de um único enlace intermitente.
- Um canal lotado é uma probabilidade, não um volume. Colisões e retransmissões escalam com o número de rádios disputando os mesmos slots — e passado um ponto, mais tráfego significa menos vazão.
- “Canal diferente” não é “sem interferência” em 2.4 GHz. Só 1, 6 e 11 não se sobrepõem, e o “escuta antes de falar” não te protege de um sinal que o rádio não consegue decodificar.
- Confira o modo de operação do Wi-Fi. Um ponto de acesso silenciosamente configurado em
802.11bcobra imposto de todo dispositivo do canal, não só dos próprios. É uma opção num menu, e valeu por volta de 7×. - Meça antes e depois. “Parece mais rápido” não é resultado. Taxa de retransmissão, taxa negociada e um download medido entre as janelas de interferência — isso sim é resultado.