Skip to content
DBDeependra Bhatta~/notes
CI/CD#webhooks · #github · #jenkins

Trigger Jenkins Builds with GitHub Webhooks

Connect GitHub to Jenkins so every push to a branch starts the pipeline, using a GitHub token, the githubPush trigger and ngrok to expose a local Jenkins.

· updated · 6 min read
ON THIS PAGE

A CI server that waits for someone to click Build Now is not continuous integration. This guide configures GitHub to send a webhook on every push to the develop branch so Jenkins starts the pipeline automatically. Because the Jenkins server runs in a private Vagrant VM that GitHub cannot reach, ngrok provides the public URL.

Prerequisites

  • Jenkins with a working pipeline from the earlier parts of this series, such as Jenkins Pipelines.
  • Admin access to the GitHub repository and a GitHub personal access token.
  • A free ngrok account.

How the flow works

  1. You push a commit to GitHub.
  2. GitHub sends an HTTP POST (the webhook) to <jenkins-url>/github-webhook/.
  3. The Jenkins GitHub plugin finds jobs that use this repository and have the GitHub push trigger.
  4. Those jobs check the repository for changes on their branch and start a build if there are any.

Step 1: Install the plugins

Go to Manage Jenkins → Plugins → Available plugins and install:

  • GitHub plugin (provides the push trigger and the /github-webhook/ endpoint)
  • GitHub Integration
  • Pipeline: GitHub (if not already installed)

Restart Jenkins after the install.

Step 2: Add a GitHub server in Jenkins

Go to Manage Jenkins → System, find the GitHub section and add a GitHub Server:

  • Name: GitHub (any name)
  • API URL: https://api.github.com
  • Credentials: click Add → Jenkins and create a Secret text credential. The secret is a GitHub personal access token; give it an ID such as github-token.
  • Click Test connection. It should say the credentials are verified.
  • Tick Manage hooks.

Jenkins GitHub Server settings with API URL, personal access token credential, credentials verified and Manage hooks ticked

Click Save. With Manage hooks on, Jenkins can create webhooks in GitHub by itself; the token needs hook admin scopes for that, as described in the GitHub plugin docs. I still added my webhook by hand (Step 5), because GitHub cannot reach a private Vagrant IP.

Step 3: Add the trigger to the Jenkinsfile

GRVJenkinsfile
pipeline {
    agent none
 
    triggers {
        githubPush()
    }
 
    environment {
        mydockerimage = "harbor.registry.local/jenkins/mylocalimage"
    }
 
    stages {
        // your existing stages
    }
}

githubPush() tells Jenkins to start this job when GitHub reports a push. It does not pick the branch itself; the branch comes from the job's SCM settings (Step 6). Commit and push the Jenkinsfile.

Step 4: Expose Jenkins with ngrok

Exposing the VM's port 8080 directly to the internet was not possible in my lab, so I used ngrok. ngrok creates a public HTTPS URL that forwards to a local port.

After installing ngrok, sign up, add your auth token on the machine, and start a tunnel to Jenkins:

terminal
$ ngrok config add-authtoken <your-ngrok-token>
$ ngrok http 8080

ngrok http 8080 runs in the foreground and occupies the terminal. The following script runs it in the background and prints the webhook URL:

SHstart-ngrok.sh
#!/bin/bash
 
PORT=8080
LOGFILE="ngrok.log"
 
# Kill any existing ngrok process on this port (optional)
pkill -f "ngrok http $PORT"
 
# Start ngrok in background and save logs
nohup ngrok http $PORT > $LOGFILE 2>&1 &
 
# Wait for ngrok to initialize
sleep 5
 
# Fetch the public HTTPS URL from ngrok's local API
NGROK_URL=$(curl -s http://localhost:4040/api/tunnels \
  | grep -o 'https://[a-zA-Z0-9.-]*.ngrok-free.app' | head -n 1)
 
if [[ -n "$NGROK_URL" ]]; then
  echo "Your Jenkins webhook URL is:"
  echo "$NGROK_URL/github-webhook/"
  echo ""
  echo "Use this URL in your GitHub webhook settings."
else
  echo "Failed to get ngrok URL. Check logs in $LOGFILE"
fi

ngrok serves a small local API on port 4040, which the script reads to find the public URL. To check or stop the tunnel:

terminal
$ ps aux | grep ngrok
$ curl http://localhost:4040/api/tunnels
$ pkill ngrok

Terminal: ngrok process running, tunnels API returning the public URL, then pkill ngrok and curl failing to connect

Step 5: Add the webhook in GitHub

In the repository, open Settings → Webhooks → Add webhook:

  • Payload URL: the ngrok URL plus /github-webhook/, for example https://<id>.ngrok-free.app/github-webhook/
  • Content type: application/x-www-form-urlencoded (I used this; the plugin also accepts application/json)
  • Keep SSL verification enabled and save.

GitHub repository webhook settings with the ngrok payload URL ending in /github-webhook/ and form-urlencoded content type

Step 6: Configure the pipeline job

In the pipeline job's configuration, tick GitHub hook trigger for GITScm polling. (Running a build with githubPush() in the Jenkinsfile ticks this box automatically.)

Jenkins job triggers with GitHub hook trigger for GITScm polling ticked

Under Pipeline, choose Pipeline script from SCM, select Git and enter the repository URL. A public repository needs no credentials.

Pipeline script from SCM using Git with repository URL https://github.com/dipen674/Ansible_Project.git

Set the Branch Specifier to the branch that should trigger builds (*/develop here) and leave Script Path as Jenkinsfile.

Branch specifier */develop and script path Jenkinsfile in the Jenkins pipeline SCM settings

Now a push to develop starts the pipeline without anyone clicking Build Now.

Troubleshooting

ProblemCause and fix
Webhook worked yesterday, fails todayThe free ngrok URL changed when I restarted ngrok (my screenshots show two different URLs). Update the payload URL in GitHub.
GitHub shows an error for the deliveryOpen the webhook's Recent Deliveries tab to see the response code. Check that the URL ends with /github-webhook/, including the last slash.
curl: (7) Failed to connect to localhost port 4040ngrok is not running. Start it again with the script.
Push arrives but no build startsRun the pipeline once by hand so Jenkins registers githubPush(), and check that the push was to the branch in Branch Specifier.
Test connection failsThe token is wrong or expired. Create a new token and update the Secret text credential.

Key takeaways

  • GitHub sends a POST to <jenkins-url>/github-webhook/; the GitHub plugin turns it into a build.
  • githubPush() sets the trigger; the job's SCM branch decides which pushes count.
  • Run the pipeline once by hand so the trigger is registered.
  • A Jenkins on a private network needs a tunnel such as ngrok, and the free URL changes on every restart.
  • Recent Deliveries in GitHub is the first place to look when a webhook does nothing.

Next in this series: SonarQube and Nexus in a Jenkins Pipeline.