Warum GitHub-Webhooks gegen einen Jenkins hinter VPN in einen Timeout laufen
GitHub stellt Webhooks eingehend zu, deshalb weist ein VPN, das Jenkins schützt, sie ab. Leiten Sie die Zustellung nach außen über einen Relay weiter oder ersetzen Sie den Webhook durch einen Agenten, der pollt.
Die Zustellungsseite zeigt einen Timeout, und Jenkins protokolliert nichts – das ist die Signatur einer Verbindung, die nie ankam. GitHub sendet einen Webhook als ausgehenden HTTP POST aus der eigenen Infrastruktur an die konfigurierte Payload-URL. Ein VPN schützt Jenkins, indem es genau diese Art von Verbindung ablehnt. Auf keiner der beiden Seiten ist etwas kaputt. Die Richtung der Anfrage ist das Problem.
Was die Zustellung tatsächlich versucht
GitHub löst den Hostnamen in der Payload-URL auf und verbindet sich aus dem öffentlichen Internet damit. Zeigt diese URL auf eine private Adresse oder auf einen Namen, der nur innerhalb Ihres Netzwerks auflöst, schlägt der Versuch fehl, bevor eine Anfrage gestellt wird. Zeigt sie auf einen öffentlichen Namen, den Ihr Edge verwirft, läuft der Versuch stattdessen in einen Timeout.
Der Unterschied ist für die Diagnose wichtig. Ein DNS-Fehler und ein gefilterter Port sehen beide so aus, als wäre auf der Jenkins-Seite nichts passiert, und beide erscheinen bei GitHub als fehlgeschlagene Zustellung mit einem anderen angehängten Grund. Lesen Sie diesen Grund, bevor Sie die URL ändern.
Ein Tunnel, der nach außen wählt, erzeugt keinen Listener. Genau diesen Teil erwarten Leute anders funktionierend.
Drei Wege, die Richtung der Verbindung zu korrigieren
Jede Lösung ändert, wer die Verbindung initiiert, und es gibt nur drei Formen.
| 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 |
Polling ist die am wenigsten elegante und die am einfachsten zu betreibende Variante. Ein Relay liefert nahezu sofortiges Feedback, ohne einen Port zu öffnen. Ein Runner ist meist die richtige Antwort, wenn Payload-Vertraulichkeit einen Dritten ausschließt, weil der Job auf einer Maschine laufen kann, die bereits im Netzwerk steht.
Wählen Sie nach dem, was Sie betreiben können, nicht nach dem, was modern klingt.
Eine Zustellung mit smee nach außen weiterleiten
Erstellen Sie einen Kanal beim Relay-Dienst und behalten Sie dessen URL. Installieren Sie im Netzwerk den Client und leiten Sie Zustellungen an den Pfad weiter, den Jenkins erwartet. Die Payload-URL in den Repository-Einstellungen wird zur Kanal-URL, mit dem Inhaltstyp application/json.
sudo npm install --global smee-client
smee -u CHANNEL_URL --path /github-webhook/ --port 8080Drei Details entscheiden, ob es funktioniert. Der Pfad muss dem entsprechen, was Jenkins für GitHub-Ereignisse erwartet, standardmäßig /github-webhook/. Jenkins muss auf dem Port lauschen, den Sie dem Client gegeben haben. Und die im Job konfigurierte Jenkins-URL muss mit diesem Pfad übereinstimmen, sonst kommt das Ereignis an und wird dann verworfen.
Ein fehlender oder überzähliger abschließender Schrägstrich erzeugt einen 404, der wie eine fehlgeschlagene Zustellung aussieht und keine ist.
So betreiben, dass es die Woche übersteht
Ein Client im Vordergrund stirbt mit dem Terminal, und die Webhooks laufen einen Tag und hören dann auf. Geben Sie ihm eine Unit mit Restart=always, führen Sie sie als Jenkins-Benutzer aus und lesen Sie das Journal nach der ersten echten Zustellung. Genau dieser letzte Schritt unterscheidet ein funktionierendes Relay von einem konfigurierten.
[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.targetTesten Sie mit einem echten Push statt mit einer Replay-Schaltfläche. Ein Replay übt die gespeicherte Payload des Relays aus, nicht den Weg von GitHub zu Ihrem Kanal, kann also bestehen, während die Live-Zustellung weiterhin fehlschlägt.
Alarmieren Sie, wenn die Unit stoppt. Ein Relay, das ausgefallen ist, ist konstruktionsbedingt still, und Stille ist genau das, was Sie bereits debuggen.
Was das Relay sieht – und wann man keines einsetzen sollte
Ein Relay terminiert die Payload und sieht daher Repository-Namen, Commit-Daten und alles andere, was das Ereignis trägt. Behandeln Sie die Kanal-URL als öffentlichen Endpunkt. Lassen Sie das geheime Jenkins-Token konfiguriert, damit gefälschte Zustellungen abgelehnt werden, und beschränken Sie das von Jenkins verwendete Token auf das nötige Minimum.
Wenn Payload-Vertraulichkeit das ausschließt, ist ein selbst gehosteter Runner oder ein authentifizierter Reverse-Tunnel die Antwort.
Ein Relay ist jetzt Infrastruktur und verdient dieselbe Prüfung wie der Build, den es auslöst. Rotieren Sie den Kanal, wenn er leckt, und notieren Sie das Datum, an dem Sie zuletzt eine Live-Zustellung verifiziert haben. Setzen Sie dieses Datum im Runbook neben die Kanal-URL. Ein Relay, das ein Jahr lang niemand geprüft hat, ist ein öffentlicher Endpunkt, den niemand betreut.