# Jenkins CI/CD Pipeline for a Dockerized Node.js Application: Manual Trigger vs Automatic Trigger Using GitHub Webhooks

> Source: <https://dev.to/omkarsharma2821/jenkins-cicd-pipeline-for-a-dockerized-nodejs-application-manual-trigger-vs-automatic-trigger-1j5b>
> Published: 2026-05-23 08:32:33+00:00

Have you ever pushed code to GitHub and wished your application could automatically build and deploy itself without logging into a server or clicking a button in Jenkins? In this article, you'll learn how to build a complete CI/CD pipeline for a Dockerized Node.js application using Jenkins, starting with manual deployments and progressing to fully automated deployments using GitHub webhooks.

We will cover:

- Creating a Jenkins pipeline
- Building a Docker image
- Deploying a container
- Triggering builds manually
- Triggering builds automatically
- GitHub Personal Access Tokens
- Fine-grained vs Classic Tokens
- Jenkins credentials
- GitHub webhooks
- Required Jenkins plugins
- Common errors and troubleshooting The goal is to understand not only how to configure everything but also why each component is needed.

Node.js Application Repo URL-

[https://github.com/omkarsharma2821/Node.js-App-Deploy-Github-Action]

## Architecture Overview

The complete flow looks like this:

```
Developer
    |
    | Git Push
    v
GitHub Repository
    |
    | Webhook
    v
Jenkins
    |
    | Build Docker Image
    v
Docker
    |
    | Run Container
    v
Application Running
```

Without webhooks:

```
Developer
    |
    | Git Push
    v
GitHub Repository

Jenkins Build Now (Manual Trigger)
    |
    v
Build and Deploy
```

With webhooks:

```
Developer
    |
    | Git Push
    v
GitHub Repository
    |
    v
Webhook
    |
    v
Jenkins
    |
    v
Build and Deploy Automatically
```

## Prerequisites

Before starting, ensure you have:

- Ubuntu Server
- Jenkins installed
- Docker installed
- Git installed
- GitHub repository
- Node.js application with Dockerfile Verify installations:

```
jenkins --version
docker --version
git --version
```

## Installing Docker on Jenkins Server

Install Docker:

```
sudo apt update
sudo apt install docker.io -y
```

Enable Docker:

```
sudo systemctl enable docker
sudo systemctl start docker
```

Verify:

```
docker --version
```

## Allow Jenkins to Use Docker

By default Jenkins cannot execute Docker commands.

Add Jenkins user to Docker group:

```
sudo usermod -aG docker jenkins
```

Restart Jenkins:

```
sudo systemctl restart jenkins
```

Verify:

```
sudo su - jenkins
docker ps
```

If Docker works without sudo, Jenkins is ready.

## Creating the Pipeline

Initially we created a Jenkins pipeline that manually clones the repository.

Example:

```
pipeline {
    agent any

    stages {

        stage('Clone Repository') {
            steps {
                sh '''
                    mkdir -p devops
                    cd devops
                    rm -rf Node.js-App-Deploy-Github-Action
                    git clone -b main https://github.com/username/repository.git
                '''
            }
        }

        stage('Build Image') {
            steps {
                sh '''
                    cd devops/Node.js-App-Deploy-Github-Action
                    docker build -t node-app .
                '''
            }
        }

        stage('Deploy') {
            steps {
                sh '''
                    docker run -d -p 8000:8080 node-app
                '''
            }
        }
    }
}
```

This works, but every deployment requires manually clicking:

```
Build Now
```

## Problem with Multiple Deployments

Suppose the application is already running.

Running:

```
docker run -d -p 8000:8080 node-app
```

again will fail because port 8000 is already occupied.

Error:

```
Bind for 0.0.0.0:8000 failed
```

## Better Deployment Approach

Before starting a new container, remove the old one.

```
docker rm -f node-app-container || true
```

Then start a new container:

```
docker run -d --name node-app-container -p 8000:8080 node-app
```

## Understanding docker rm -f node-app-container || true

Let's break it down.

## docker rm

Removes a container.

```
docker rm node-app-container
```

Works only if container is stopped.

### -f

Force remove.

```
docker rm -f node-app-container
```

This:

- Stops container
- Removes container

### ||

OR operator.

Syntax:

```
command1 || command2
```

If command1 fails, command2 executes.

### true

Always returns success.

```
true
```

Exit code:

```
0
```

### Final Meaning

```
docker rm -f node-app-container || true
```

If container exists:

```
Remove it
```

If container doesn't exist:

```
Ignore error and continue
```

This prevents Jenkins from failing.

## Manual Triggering

The simplest approach is manual execution.

Navigate to:

```
Jenkins Job
|
└── Build Now
```

Advantages:

- Easy to understand
Good for learning

Disadvantages:Requires human intervention

Not real CI/CD

## Automatic Triggering

The goal of CI/CD is:

```
Code Push
    |
    v
Automatic Build
    |
    v
Automatic Deployment
```

This is where GitHub webhooks come into play.

## **Required Jenkins Plugins**

Install the following Jenkins plugins before configuring the CI/CD pipeline:

### **1. Git Plugin**

- Enables Jenkins to interact with Git repositories.
- Allows Jenkins to clone repositories, fetch changes, and checkout specific branches.
- Required for integrating Jenkins with GitHub repositories.

### **2. GitHub Plugin**

- Provides integration between Jenkins and GitHub.
- Allows Jenkins to communicate with GitHub repositories and services.
- Supports GitHub-related features within Jenkins.

### **3. GitHub Integration Plugin**

- Enables GitHub webhook support.
- Allows Jenkins to automatically trigger builds when code is pushed to GitHub.
- Essential for implementing automated CI/CD workflows.

### **4. Pipeline Plugin**

- Enables support for Jenkins Pipelines.
- Allows execution of Jenkinsfiles written in Declarative or Scripted Pipeline syntax.
- Required for defining CI/CD workflows as code.

### **5. Credentials Plugin**

- Provides secure storage for sensitive information.
- Allows storing:
- GitHub Personal Access Tokens (PATs)
- Usernames and passwords
- SSH keys
- API tokens

- Prevents hardcoding secrets in Jenkins jobs and pipelines.

## **GitHub Authentication**

When Jenkins needs to access a GitHub repository, authentication requirements depend on the repository type.

### **Public Repository**

- Can typically be cloned without authentication.

Example:

```
git clone https://github.com/username/repository.git
```

### **Private Repository**

- Requires authentication.
- GitHub no longer supports account passwords for Git operations.
- A Personal Access Token (PAT) must be used instead of a password.

### **Why Use a Personal Access Token (PAT)?**

- More secure than passwords.
- Allows granular permission control.
- Can be revoked without affecting your GitHub account password.
- Recommended by GitHub for all Git operations requiring authentication.

## Classic Personal Access Token

Older token type.

Advantages:

- Simple
Easy to configure

Disadvantages:Broad permissions

Less secure

Example scopes:

```
repo
workflow
admin:repo_hook
```

## Fine-Grained Personal Access Token

Newer and recommended approach.

Advantages:

- Repository-level access
- Better security
- Granular permissions Example:

```
Repository Access:
Only selected repositories
```

Permissions:

```
Contents: Read and Write
Metadata: Read
Webhooks: Read and Write
```

## Fine-Grained vs Classic Token

| Feature | Fine-Grained | Classic |
|---|---|---|
| Security | High | Lower |
| Repository Scope | Specific | Broad |
| Permission Control | Granular | Broad |
| Recommended | Yes | Legacy |

For modern projects, prefer Fine-Grained tokens.

## Adding GitHub Token to Jenkins

Navigate to:

```
Manage Jenkins
|
Credentials
```

Select:

```
Global Credentials
```

Choose:

```
Add Credentials
```

Kind:

```
Username with Password
```

Example:

```
Username: GitHub Username
Password: Personal Access Token
```

ID:

```
github-creds
```

Save.

## Pipeline Script vs Pipeline Script from SCM

Many beginners get confused here.

## Pipeline Script

Pipeline stored inside Jenkins UI.

Example:

```
pipeline {
    agent any
}
```

Advantages:

Quick setup

Disadvantages:Not version controlled

Difficult to maintain

## Pipeline Script from SCM

Pipeline stored in GitHub repository.

Repository structure:

```
project/
|
|-- Dockerfile
|-- package.json
|-- app.js
|-- Jenkinsfile
```

Jenkins automatically downloads Jenkinsfile.

Advantages:

- Version controlled
- Industry standard
- Easier maintenance Recommended approach.

## Configuring Pipeline from SCM

Create Jenkins job.

Select:

```
Pipeline
```

Under Definition:

```
Pipeline script from SCM
```

SCM:

```
Git
```

Repository URL:

```
https://github.com/username/repository.git
```

Branch:

```
*/main
```

Script Path:

```
Jenkinsfile
```

Save.

## Creating GitHub Webhook

Navigate to:

```
GitHub Repository
|
Settings
|
Webhooks
|
Add Webhook
```

Payload URL:

```
http://JENKINS_PUBLIC_IP:8080/github-webhook/
```

Content Type:

```
application/json
```

Event:

```
Just the push event
```

Save webhook.

## Configuring Jenkins Trigger

Open job configuration.

Under Build Triggers:

Select:

```
GitHub hook trigger for GITScm polling
```

Save.

## Testing the Webhook

Push code:

```
git add .
git commit -m "testing webhook"
git push origin main
```

Expected flow:

```
GitHub Push
    |
    v
Webhook
    |
    v
Jenkins
    |
    v
Pipeline Starts
```

No manual click required.

## Common Troubleshooting

## Webhook Returns 404

Cause:

```
Wrong webhook URL
```

Correct:

```
http://SERVER-IP:8080/github-webhook/
```

## Webhook Returns 403

Cause:

```
Authentication or security issue
```

Verify:

- GitHub plugin
- GitHub integration plugin

## Webhook Returns 200 But Build Doesn't Start

Common cause:

```
Pipeline Script instead of Pipeline Script from SCM
```

or

```
Repository mapping issue
```

## Dockerfile Not Found

Example:

```
unable to evaluate symlinks in Dockerfile path
```

Cause:

Wrong working directory.

Check:

```
pwd
ls -la
```

Verify Dockerfile location.

## Permission Denied While Running Docker

Cause:

```
Jenkins not in docker group
```

Fix:

```
sudo usermod -aG docker jenkins
sudo systemctl restart jenkins
```

## Final Jenkinsfile

```
pipeline {
    agent any

    stages {

        stage('Build Image') {
            steps {
                sh '''
                    docker build -t node-app .
                '''
            }
        }

        stage('Deploy') {
            steps {
                sh '''
                    docker rm -f node-app-container || true
                    docker run -d --name node-app-container -p 8000:8080 node-app
                '''
            }
        }
    }
}
```

## Conclusion

A Jenkins pipeline can be triggered manually or automatically. Manual triggering is useful for learning and testing, but real CI/CD begins when code pushes automatically trigger builds and deployments.

The recommended production approach is:

- Store the Jenkinsfile in GitHub.
- Use Pipeline Script from SCM.
- Configure GitHub credentials using a Personal Access Token.
- Enable GitHub webhook integration.
- Use Docker for packaging and deployment.
- Remove old containers before deploying new versions. With this setup, every code push automatically builds a Docker image, deploys a fresh container, and updates the application without requiring any manual intervention.

✍️ **Author**: *Omkar Sharma*

📬 *Feel free to connect on LinkedIn or explore more on GitHub*
