Automating the build-test-deploy cycle is one of those things that feels like overhead until you've actually done it. Once you have a pipeline that runs tests on every push and deploys automatically on merge to main, you stop dreading releases.
I set up Jenkins on a cloud server to handle CI/CD for a few personal projects. The setup took an afternoon. Now every push triggers tests automatically, and pushing to main deploys to production without me touching a terminal.
I run Jenkins on Tencent Cloud Lighthouse. The 2 GB RAM / 2 vCPU plan handles a few concurrent pipelines. For more parallel jobs, upgrade to 4 GB RAM. A practical Lighthouse advantage for CI/CD: the spec upgrade path (without re-provisioning) means you can scale Jenkins to your actual build load without recreating the configuration from scratch. The snapshot feature also lets you back up Jenkins' home directory (which contains all jobs, credentials, and plugins) before version upgrades — Jenkins upgrades can occasionally break plugins, and having a restore point is valuable.
- Key Takeaways
Jenkins is the most widely-used open source CI/CD server. Running it yourself means:
The trade-off is you manage the server and the Jenkins installation. For a developer or small team with regular build traffic, the operational overhead is low once it's configured.
| Requirement | Details |
|---|---|
| Server | Ubuntu 22.04, 2 GB+ RAM |
| Java | OpenJDK 17 (Jenkins requirement) |
| Domain | Recommended for webhook configuration |
| Open ports | 8080 (Jenkins) or 443 via Nginx proxy |
Jenkins requires Java 17 or 21:
sudo apt update
sudo apt install -y openjdk-17-jdk
java -version
# openjdk version "17.x.x"
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt update
sudo apt install -y jenkins
sudo systemctl enable jenkins
sudo systemctl start jenkins
sudo systemctl status jenkins
sudo ufw allow 8080/tcp
sudo ufw reload
Also add port 8080 in your Lighthouse console firewall rules.
Navigate to http://YOUR_SERVER_IP:8080.
You'll see the "Unlock Jenkins" screen. Get the initial admin password:
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
Paste it into the browser and click Continue.
Choose "Install suggested plugins" on the setup wizard. This installs Git integration, pipeline support, and other essentials. Takes 2–3 minutes.
Create your admin account with a strong password. This replaces the generated password.
Running Jenkins on port 8080 directly works, but setting up Nginx with HTTPS is better for security and webhook configuration:
Install Nginx:
sudo apt install -y nginx
sudo certbot --nginx -d jenkins.yourdomain.com
Create /etc/nginx/sites-available/jenkins:
server {
listen 443 ssl;
server_name jenkins.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/jenkins.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/jenkins.yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
sudo ln -s /etc/nginx/sites-available/jenkins /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Update Jenkins' URL in Manage Jenkins → System → Jenkins URL to https://jenkins.yourdomain.com.
Go to Manage Jenkins → Plugins → Available plugins and install:
| Plugin | Purpose |
|---|---|
| Pipeline | Declarative pipeline support (usually pre-installed) |
| Git | GitHub/GitLab integration |
| GitHub Integration | Webhooks from GitHub |
| SSH Agent | Use SSH keys in pipelines |
| Docker Pipeline | Build and run Docker containers in pipelines |
| Credentials Binding | Inject secrets into pipeline steps |
| Blue Ocean | Modern pipeline visualization UI |
After installation, restart Jenkins:
sudo systemctl restart jenkins
my-app-pipeline)Under Pipeline, select Pipeline script from SCM:
*/mainJenkinsfileCreate Jenkinsfile at your repo root:
pipeline {
agent any
environment {
NODE_VERSION = '20'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Install') {
steps {
sh 'npm ci'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
stage('Build') {
steps {
sh 'npm run build'
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sshagent(['production-server-key']) {
sh '''
ssh -o StrictHostKeyChecking=no ubuntu@YOUR_PROD_IP "
cd /opt/myapp &&
git pull origin main &&
npm ci --production &&
pm2 reload myapp
"
'''
}
}
}
}
post {
failure {
echo 'Build failed!'
}
success {
echo 'Build succeeded!'
}
}
}
Click Build Now in Jenkins to test the pipeline.
Automatically trigger builds on every push.
https://jenkins.yourdomain.com/github-webhook/application/jsonIn Jenkins Pipeline job settings → Build Triggers → Check GitHub hook trigger for GITScm polling.
Push a commit to your repository. The Jenkins pipeline should trigger within seconds.
production-server-keyubuntuAdd Jenkins server's public key to your production server's ~/.ssh/authorized_keys:
# On Jenkins server, get the Jenkins user's public key
sudo -u jenkins cat ~/.ssh/id_rsa.pub
# On production server
echo "PUBLIC_KEY_HERE" >> ~/.ssh/authorized_keys
sudo -u jenkins ssh ubuntu@YOUR_PROD_IP "echo 'SSH connection works'"
My pipelines were passing locally but failing in Jenkins with npm: command not found.
Jenkins runs as the jenkins user, which doesn't inherit your PATH or nvm setup. Node.js installed via nvm for your regular user is invisible to Jenkins.
The fix: Install Node.js system-wide instead of via nvm:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt install -y nodejs
Or, use the NodeJS Jenkins plugin to manage Node.js versions per job:
tools { nodejs 'nodejs-20' } at the topThe plugin approach is cleaner for managing multiple Node.js versions across different projects.
| Issue | Likely Cause | Fix |
|---|---|---|
| Jenkins won't start | Java not installed | sudo apt install openjdk-17-jdk |
| 403 Forbidden on webhook | CSRF protection | Use API token in webhook URL |
| Pipeline can't find commands | PATH not set | Install tools system-wide or use Jenkins tool management |
| Disk fills up | Build artifacts accumulating | Set Discard old builds in pipeline settings |
| Out of memory during build | Insufficient RAM | Upgrade to 4 GB RAM or limit concurrent builds |
| SSH deploy fails | Key not authorized | Check authorized_keys on production server |
| Slow build times | Sequential execution | Add parallel { } blocks for independent stages |
✅ What you built:
Once the initial configuration is done, adding a new project takes about 5 minutes: add a Jenkinsfile to the repo, create a Jenkins job pointing at that repo, and add a webhook. The pipeline runs on its own from there.
What's the difference between CI and CD?
CI (Continuous Integration) automatically runs tests when code is pushed. CD (Continuous Deployment/Delivery) automatically deploys tested code to servers. Together they eliminate manual build-test-deploy cycles.
How do I store secrets (API keys, passwords) in Jenkins?
Use the CI/CD platform's secrets management — never put secrets in your repository. Reference them as environment variables in your pipeline config. Lighthouse server credentials go in deployment secrets.
What happens if a deployment fails partway through?
Implement a rollback strategy: tag git commits before deployment, keep the previous release available, and have a procedure to revert. Lighthouse snapshots provide a full-server rollback point.
How do I deploy to multiple environments (staging, production) from the same pipeline?
Use branch-based or tag-based triggers. Pushes to develop deploy to staging; tagged releases or merges to main deploy to production. Configure different deployment targets per environment.
👉 Get started with Tencent Cloud Lighthouse
👉 View current pricing and launch promotions
👉 Explore all active deals and offers