Por que os webhooks do GitHub expiram contra um Jenkins atrás de uma VPN
O GitHub envia os webhooks para dentro, então uma VPN que protege o Jenkins os rejeita. Encaminhe a entrega para fora com um relay ou substitua o webhook por um agente que faça sondagem.
A página de entrega mostra um tempo limite e o Jenkins não registra nada, que é a assinatura de uma conexão que nunca chegou. O GitHub envia um webhook como um HTTP POST de saída da sua própria infraestrutura para o payload URL que você configurou. Uma VPN protege o Jenkins recusando exatamente esse tipo de conexão. Nada está quebrado de nenhum dos lados. O problema é a direção da requisição.
O que a entrega realmente tenta
O GitHub resolve o nome do host no payload URL e se conecta a ele a partir da internet pública. Se esse URL aponta para um endereço privado, ou para um nome que só resolve dentro da sua rede, a tentativa falha antes que qualquer requisição seja feita. Se aponta para um nome público que a sua borda descarta, a tentativa expira em vez disso.
A distinção importa para o diagnóstico. Uma falha de DNS e uma porta filtrada parecem ambas que nada aconteceu do lado do Jenkins, e ambas aparecem no GitHub como uma entrega falha com um motivo diferente anexado. Leia esse motivo antes de mudar o URL.
Um túnel que disca para fora não cria um ouvinte. É essa a parte que as pessoas esperam que funcione de outra forma.
Três maneiras de corrigir a direção da conexão
Cada solução muda quem inicia a conexão, e existem apenas três formas.
| Approach | Who initiates | What you give up |
|---|---|---|
| Relay service | An outbound client inside the network | A third party sees every payload |
| Reverse tunnel or ingress | The public edge, into a controlled listener | An inbound surface you must secure |
| Runner or polling | The agent, outbound to GitHub | Instant delivery, replaced by a schedule |
A sondagem é a menos elegante e a mais fácil de operar. Um relay mantém feedback quase instantâneo sem abrir uma porta. Um runner costuma ser a resposta certa quando a confidencialidade do payload exclui um terceiro, porque o trabalho pode rodar numa máquina que já está dentro da rede.
Escolha pelo que você consegue operar, não pelo que soa moderno.
Encaminhe uma entrega para fora com smee
Crie um canal no serviço de relay e guarde o URL dele. Dentro da rede, instale o cliente e encaminhe as entregas para o caminho que o Jenkins espera. O payload URL nas configurações do repositório passa a ser o URL do canal, com o tipo de conteúdo definido como application/json.
sudo npm install --global smee-client
smee -u CHANNEL_URL --path /github-webhook/ --port 8080Três detalhes decidem se funciona. O caminho tem de corresponder ao que o Jenkins espera para eventos do GitHub, que por padrão é /github-webhook/. O Jenkins tem de estar escutando na porta que você deu ao cliente. E o Jenkins URL configurado na tarefa tem de concordar com esse caminho, senão o evento chega e depois é descartado.
Uma barra final que não corresponde produz um 404 que se lê como falha de entrega e não é.
Executar de forma que sobreviva à semana
Um cliente em primeiro plano morre com o terminal, e os webhooks funcionam um dia e depois param. Dê a ele uma unit com Restart=always, execute como o usuário Jenkins e leia o journal depois da primeira entrega real. Esse último passo é o que separa um relay que funciona de um configurado.
[Unit]
Description=smee webhook relay
After=network.target
[Service]
Type=simple
Restart=always
RestartSec=2
User=jenkins
ExecStart=/usr/bin/smee -u CHANNEL_URL --path /github-webhook/ --port 8080
[Install]
WantedBy=multi-user.targetTeste com um push real em vez do botão de repetição. Uma repetição exercita o payload armazenado do relay, não o caminho do GitHub até o seu canal, então pode passar enquanto a entrega ao vivo ainda falha.
Avise quando a unit parar. Um relay fora do ar é silencioso por construção, e o silêncio é exatamente o que você já está depurando.
O que o relay pode ver, e quando não usar um
Um relay termina o payload, então vê nomes de repositórios, dados de commit e tudo o mais que o evento carrega. Trate o URL do canal como um endpoint público. Mantenha o token secreto do Jenkins configurado para que entregas forjadas sejam rejeitadas, e limite o token que o Jenkins usa ao mínimo necessário.
Se a confidencialidade do payload exclui isso, um runner auto-hospedado ou um túnel reverso autenticado é a resposta.
Um relay agora é infraestrutura, e merece a mesma revisão que o build que ele dispara. Rotacione o canal se ele vazar, e anote a data em que você verificou pela última vez uma entrega ao vivo. Coloque essa data no runbook ao lado do URL do canal. Um relay que ninguém revisou durante um ano é um endpoint público que ninguém possui.