Perché i webhook di GitHub scadono contro un Jenkins dietro una VPN
GitHub invia i webhook verso l’interno, quindi una VPN che protegge Jenkins li rifiuta. Fai uscire la consegna tramite un relay, oppure sostituisci il webhook con un agente che esegue polling.
La pagina di consegna mostra un timeout e Jenkins non registra nulla, che è la firma di una connessione mai arrivata. GitHub invia un webhook come HTTP POST in uscita dalla propria infrastruttura verso l’URL di payload configurato. Una VPN protegge Jenkins rifiutando esattamente quel tipo di connessione. Nulla è rotto su nessuno dei due lati. Il problema è la direzione della richiesta.
Cosa tenta davvero la consegna
GitHub risolve il nome host nell’URL di payload e vi si connette dall’internet pubblico. Se quell’URL punta a un indirizzo privato, o a un nome che si risolve solo all’interno della tua rete, il tentativo fallisce prima che venga fatta qualsiasi richiesta. Se punta a un nome pubblico che il tuo edge scarta, il tentativo scade invece.
La distinzione conta per la diagnosi. Un guasto DNS e una porta filtrata sembrano entrambi che non sia successo nulla sul lato Jenkins, ed entrambi compaiono su GitHub come consegna fallita con un motivo diverso allegato. Leggi quel motivo prima di cambiare l’URL.
Un tunnel che compone verso l’esterno non crea un listener. È la parte che le persone si aspettano funzioni diversamente.
Tre modi per correggere la direzione della connessione
Ogni soluzione cambia chi avvia la connessione, e ci sono solo tre forme.
| 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 |
Il polling è il meno elegante e il più facile da gestire. Un relay mantiene un riscontro quasi immediato senza aprire una porta. Un runner è di solito la risposta giusta quando la riservatezza del payload esclude una terza parte, perché il lavoro può girare su una macchina che sta già dentro la rete.
Scegli in base a ciò che puoi gestire, non in base a ciò che suona moderno.
Fai uscire una consegna con smee
Crea un canale sul servizio di relay e conservane l’URL. Dentro la rete, installa il client e inoltra le consegne al percorso che Jenkins si aspetta. L’URL di payload nelle impostazioni del repository diventa l’URL del canale, con il tipo di contenuto impostato su application/json.
sudo npm install --global smee-client
smee -u CHANNEL_URL --path /github-webhook/ --port 8080Tre dettagli decidono se funziona. Il percorso deve corrispondere a ciò che Jenkins si aspetta per gli eventi GitHub, che per impostazione predefinita è /github-webhook/. Jenkins deve ascoltare sulla porta che hai assegnato al client. E l’URL di Jenkins configurato nel job deve concordare con quel percorso, altrimenti l’evento arriva e poi viene scartato.
Una barra finale che non corrisponde produce un 404 che si legge come una consegna fallita e non lo è.
Eseguirlo in modo che sopravviva alla settimana
Un client in primo piano muore con il terminale, e i webhook funzionano per un giorno e poi si fermano. Dagli una unit con Restart=always, eseguila come utente Jenkins e leggi il journal dopo la prima consegna reale. È quest’ultimo passaggio a separare un relay funzionante da uno configurato.
[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.targetProva con un push reale invece del pulsante di ripetizione. Una ripetizione esercita il payload memorizzato del relay, non il percorso da GitHub al tuo canale, quindi può passare mentre la consegna dal vivo fallisce ancora.
Avvisa quando la unit si ferma. Un relay abbattuto è silenzioso per costruzione, e il silenzio è proprio quello che stai già debuggando.
Cosa può vedere il relay, e quando non usarne uno
Un relay termina il payload, quindi vede nomi dei repository, dati di commit e tutto il resto che l’evento trasporta. Tratta l’URL del canale come un endpoint pubblico. Mantieni configurato il token segreto di Jenkins così che le consegne false vengano rifiutate, e limita il token usato da Jenkins al minimo necessario.
Se la riservatezza del payload lo esclude, un runner self-hosted o un tunnel inverso autenticato è la risposta.
Un relay ormai è infrastruttura, e merita la stessa revisione della build che innesca. Ruota il canale se perde, e annota la data in cui hai verificato l’ultima volta una consegna dal vivo. Metti quella data nel runbook accanto all’URL del canale. Un relay che nessuno ha esaminato per un anno è un endpoint pubblico che nessuno possiede.