You can open Jenkins over the VPN and still watch GitHub report a failed webhook, because those are two different connections with two different owners. The browser rides a tunnel your laptop negotiated; GitHub's delivery service starts on the public internet and has no route into the private network. Repository access does not change that, even though Jenkins itself may fetch from the same repository without trouble. Pick an ingress, a relay or polling, then test the path the event actually takes.

A browser session proves only one direction

A VPN connection answers one question: can this laptop reach the internal host. Webhook delivery asks a different one: can an external service open a connection to that host. Jenkins fetching a repository is outbound traffic and says nothing about inbound reachability. Keep both directions on separate lines of your diagram, including which side initiates each one.

Read the delivery record before changing anything. A timeout, a connection reset and an accepted request that matched no job have three different owners: network, proxy, and trigger configuration.

Option A: expose a narrow endpoint

If the organization already publishes an approved ingress, expose the webhook path instead of the dashboard. That usually means a reverse proxy rule that accepts POSTs on the hook URL and forwards them to Jenkins while the administration interface stays unreachable from outside.

curl -sS -o /dev/null -w "%{http_code}\n" -X POST https://jenkins.example.com/github-webhook/

Run that test from a network without VPN access, because a success from inside the tunnel proves nothing. The endpoint should reject requests that lack the shared secret, which GitHub sends as a signature header, and it should accept only the single path and method you published. A public Jenkins console is not a webhook fix; it is an incident waiting for the next scanner to find it. Scope the rule tightly enough that the rest of the application keeps the access controls it had before.

Option B: invert the direction with a relay

Where inbound exposure will not be approved, a small client inside the network can hold an outbound connection to a relay and receive forwarded events. The relay then becomes part of the delivery path, so its availability and authentication matter as much as the build job does.

ssh -N -R 9000:localhost:8080 relay.example.net

Jenkins' guidance on webhooks behind firewalls describes this shape, and it is worth reading before writing a custom forwarder. Terminate TLS at the relay, verify the signature before the event reaches the job, and monitor the outbound link, because a dropped tunnel looks exactly like an event that was never sent. Confirm the relay preserves the request body byte for byte as well, since signature checks fail on JSON that has been parsed and re-encoded along the way.

Option C: poll the repository instead

Polling trades latency for simplicity and needs no inbound path at all. Jenkins can poll on a schedule, or a small job can query the API and start a build when it sees an unfamiliar revision.

curl -sS -u "$USER:$TOKEN" "https://api.github.com/repos/OWNER/REPO/commits?per_page=1"

Each poll spends API calls and adds a delay between push and build, which becomes visible on busy repositories and shared rate limits. It also needs credentials stored wherever the poller runs, so scope the token to read-only repository access and rotate it like any other secret. Choose this when event volume is low or when no ingress will ever be approved, and say so in the job description so nobody later wonders why builds lag.

Accept a real delivery, not a page load

Whichever option you picked, the acceptance test is an event sent by the source platform, not a browser tab opened from a privileged laptop. Push an empty commit to a scratch branch and read the delivery response code, the relay log or the polling job's output, in that order. A 200 from the endpoint with no build means the trigger filter is wrong; a timeout means the path is still closed. Record which of the three designs is in use, because the next person to debug will otherwise repeat the browser test and reach the same dead end.

Apply the same reasoning to payment callbacks and other outside notifications: each needs its own route into the private application, even when every human already holds a VPN session. The delivery path belongs in the application design, not in a networking footnote.

Sɛbɛn minnu bɛ tali kɛ