UpCloud
Effortless global cloud infrastructure for SMBs
Introducing
If you’re interested in what we have to offer, contact sales or fill out a contact form.
Our support live chat is available for our customers 24/7. You can also email our support team.
Send us an email to give feedback or to say hello.
Start a new journey
Why Partner with UpCloud?
I’ve been passionate about the hosting industry since 2001. Before founding UpCloud, my first company grew to become one of Finland’s largest shared web hosting providers, serving over 30,000 customers. Along the way, I faced the same challenges many of you know well—24/7 on-call responsibilities, solving technical issues, and managing customer inquiries.
At UpCloud, we’ve designed a platform that solves these challenges, offering reliability, scalability, and unparalleled support. We understand the pressures you face because we’ve been there too. Partner with us, and let’s help you focus on growing your business while we handle the rest.
Sincerely, Joel Pihlajamaa CTO, Founder
Login
Sign up
Updated on 30.6.2025
Jenkins is one of the most popular open-source automation servers for setting up CI/CD pipelines, and when paired with UpCloud, it becomes a powerful platform for deploying Node.js applications. Jenkins gives you full control over your build and deployment processes, making it ideal for teams that want a highly customizable pipeline. Combined with UpCloud’s high-performance virtual machines and predictable pricing, it’s a solid choice for developers looking to self-host and scale their infrastructure.
In this tutorial, you’ll learn how to set up a self-hosted Jenkins server on UpCloud and use it to automatically deploy a Node.js application from GitHub to another UpCloud server. We’ll walk through provisioning the Jenkins instance, configuring build jobs, setting up SSH-based deployment, and testing the full end-to-end workflow. By the end, you’ll have a fully functioning CI/CD pipeline tailored to your infrastructure.
Jenkins and UpCloud make a great combination for developers who want full control over their deployment workflows without relying on third-party automation platforms. With Jenkins, you can customize every step of your CI/CD pipeline, from pulling code from GitHub to running tests and deploying to production. It’s especially useful for teams that want to self-host their automation and fine-tune their build and release processes without being locked into a proprietary system.
UpCloud, on the other hand, provides a fast, reliable, and cost-effective cloud hosting environment that pairs perfectly with Jenkins. You can spin up dedicated servers with just the right specs for your application, and scale vertically as needed without downtime. With features like floating IPs, private networking, and backups, UpCloud gives you the flexibility to run production workloads with confidence, whether you’re hosting a small API service or a full-stack web app.
Using Jenkins on UpCloud means you’re running your entire CI/CD pipeline on infrastructure you control. It’s an ideal setup for teams with specific compliance requirements, performance needs, or deployment strategies that are too complex for hosted solutions. Whether you’re a solo developer or managing a growing team, deploying from Jenkins to UpCloud offers a powerful, flexible foundation for modern app development.
In this tutorial, you will first fork this GitHub repository that has a basic Node.js app. After that, you’ll set up a new server on UpCloud where the app will be hosted. Finally, you will deploy the app manually on the server for the first time.
Next, you’ll set up another UpCloud server to host an instance of Jenkins. You will then configure a pipeline on this Jenkins instance to handle future deployments of your Node.js app for you. Every time you make a change and push it to GitHub, your Jenkins instance will automatically update the app on your UpCloud server. This helps you skip the manual steps and keeps your app always up to date.
To follow along, you will need the following:
Once you have these in place, let’s now take a quick look at the example app that you will deploy through the pipeline in this tutorial. The app in the repository is a random facts generator. It has a list of a few facts in the source code, and it picks and returns a fact from it randomly on each API call:
// contents of index.js const express = require('express'); const app = express(); const PORT = process.env.PORT || 5001; // Array of random facts const facts = [ "Honey never spoils.", "A group of flamingos is called a 'flamboyance.'", "Bananas are berries, but strawberries aren't.", "Octopuses have three hearts.", "Australia is believed to have lost to emus in the Great Emu War of 1932", "A jiffy is an actual unit of time: 1/100th of a second.", "Cows have best friends and get stressed when they are separated.", "The shortest war in history lasted 38 minutes.", "The Eiffel Tower can be 15 cm taller during the summer.", "A small child could swim through the veins of a blue whale." ]; // Serve static files (HTML, CSS, JS) app.use(express.static('public')); // Endpoint to get a random fact app.get('/random-fact', (req, res) => { const randomIndex = Math.floor(Math.random() * facts.length); res.json({ fact: facts[randomIndex] }); }); // Start the server app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); });
It also serves a simple HTML page on its root path (/). This page contains a title, a button to get a random fact, a placeholder for the random fact to be displayed to the user, and a footer. Here’s what the code for this page looks like:
/
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Random Facts Generator</title> <style> body { font-family: Arial, sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 98vh; background-color: #f5f5f5; } button { padding: 10px 20px; font-size: 16px; cursor: pointer; } p { margin-top: 20px; font-size: 20px; text-align: center; } #footer { position: absolute; bottom: 10px; font-size: 0.8rem; } </style> </head> <body> <h1>Random Fact Generator</h1> <button id="generate">Get a Random Fact</button> <p id="fact"></p> <p id="footer">Made in 2024</p> <script> document.getElementById('generate').onclick = async () => { const response = await fetch('/random-fact'); const data = await response.json(); document.getElementById('fact').innerText = data.fact; }; </script> </body> </html>
You can try running the app locally using the following commands:
# Clone the repo git clone https://github.com/krharsh17/random-facts-generator cd random-facts-generator # Install dependencies yarn # Run the development server yarn dev
Now, you can go to http://localhost:5001 to view the app in action:
Once you click the Get a Random Fact button, you will, indeed, get a random fact.
At this point, please make sure that you fork a copy of this repo to your GitHub account. This is important because you will need to make changes to the source code of the app and then push the changes to your remote copy of the repository to trigger the Jenkins pipeline.
Now, let’s move on to setting up the UpCloud server where you will deploy this application.
upctl
UpCloud provides two methods to create web servers: the web dashboard and the upctl CLI. In this section, you will create an UpCloud server through upctl. You can find detailed instructions on how to set up upctl on your system here based on your local machine’s operating system.
upctl.
Once you have set up upctl correctly and logged into it with your UpCloud account, you can try it out by running the following command to print the details of your UpCloud account:
✗ upctl account show Username: <your-upcloud-username> Credits: <your-credits> Resource Limits: Cores: 100 Detached Floating IPs: 10 Load balancers: 50 Managed object storages: 20 Memory: 307200 Network peerings: 100 Networks: 100 NTP excess GiB: 0 Public IPv4: 20 Public IPv6: 100 Storage HDD: 10240 Storage MaxIOPS: 10240 Storage SSD: 10240
Now you’re ready to create a new server! But before doing that, it is important to understand the various options you will need to supply to the upctl create server command.
upctl create server
You’ll need to choose the physical location of your server. Ideally, you should choose the location closest to your target users so that they face the least latency when trying to access your app.
To view a list of available zones, run upctl zone list:
upctl zone list
✗ upctl zone list ID Description Public ───────── ────────────── ──────── au-syd1 Sydney #1 yes de-fra1 Frankfurt #1 yes es-mad1 Madrid #1 yes fi-hel1 Helsinki #1 yes fi-hel2 Helsinki #2 yes nl-ams1 Amsterdam #1 yes pl-waw1 Warsaw #1 yes se-sto1 Stockholm #1 yes sg-sin1 Singapore #1 yes uk-lon1 London #1 yes us-chi1 Chicago #1 yes us-nyc1 New York #1 yes us-sjo1 San Jose #1 yes
Next, you need to choose a server plan. The server plan defines the CPU, RAM, and storage space available to your server. UpCloud provides you with a range of options from development-focused, small-sized plans for testing purposes and personal projects to large and cost-effective cloud-native plans that unbundle storage and IPv4 addresses from the plans. You can learn more about the available plans here.
You can list the available server plans by running upctl server plans:
upctl server plans:
✗ upctl server plans General purpose Name Cores Memory Storage size Storage tier Transfer out (GiB/month) ────────────────────────── ─────── ──────── ────────────── ────────────── ────────────────────────── 1xCPU-1GB 1 1024 25 maxiops 1024 1xCPU-2GB 1 2048 50 maxiops 2048 CLOUDNATIVE-1xCPU-4GB 1 4096 0 1024 CLOUDNATIVE-1xCPU-8GB 1 8192 0 2048 2xCPU-2GB 2 2048 60 maxiops 3072 CLOUDNATIVE-2xCPU-4GB 2 4096 0 2048 2xCPU-4GB 2 4096 80 maxiops 4096 CLOUDNATIVE-2xCPU-8GB 2 8192 0 2048 CLOUDNATIVE-2xCPU-16GB 2 16384 0 3072 CLOUDNATIVE-4xCPU-8GB 4 8192 0 2048 4xCPU-8GB 4 8192 160 maxiops 5120 CLOUDNATIVE-4xCPU-16GB 4 16384 0 5120 CLOUDNATIVE-4xCPU-24GB 4 24576 0 6144 CLOUDNATIVE-4xCPU-32GB 4 32768 0 7168 CLOUDNATIVE-4xCPU-48GB 4 49152 0 14336 CLOUDNATIVE-6xCPU-16GB 6 16384 0 5120 6xCPU-16GB 6 16384 320 maxiops 6144 CLOUDNATIVE-6xCPU-24GB 6 24576 0 6144 CLOUDNATIVE-8xCPU-16GB 8 16384 0 6144 CLOUDNATIVE-8xCPU-24GB 8 24576 0 7168 CLOUDNATIVE-8xCPU-32GB 8 32768 0 9216 8xCPU-32GB 8 32768 640 maxiops 7168 CLOUDNATIVE-8xCPU-48GB 8 49152 0 14336 CLOUDNATIVE-8xCPU-64GB 8 65536 0 16384 CLOUDNATIVE-8xCPU-96GB 8 98304 0 26624 CLOUDNATIVE-8xCPU-128GB 8 131072 0 30720 CLOUDNATIVE-12xCPU-24GB 12 24576 0 8192 CLOUDNATIVE-12xCPU-32GB 12 32768 0 9216 12xCPU-48GB 12 49152 960 maxiops 9216 CLOUDNATIVE-16xCPU-32GB 16 32768 0 13312 CLOUDNATIVE-16xCPU-48GB 16 49152 0 15360 CLOUDNATIVE-16xCPU-64GB 16 65536 0 20480 16xCPU-64GB 16 65536 1280 maxiops 10240 CLOUDNATIVE-16xCPU-96GB 16 98304 0 26624 CLOUDNATIVE-16xCPU-128GB 16 131072 0 35840 CLOUDNATIVE-16xCPU-192GB 16 196608 0 46080 CLOUDNATIVE-20xCPU-64GB 20 65536 0 22528 CLOUDNATIVE-20xCPU-96GB 20 98304 0 28672 24xCPU-96GB 24 98304 1920 maxiops 12288 CLOUDNATIVE-24xCPU-256GB 24 262144 0 61440 CLOUDNATIVE-32xCPU-64GB 32 65536 0 25600 CLOUDNATIVE-32xCPU-128GB 32 131072 0 40960 32xCPU-128GB 32 131072 2048 maxiops 24576 CLOUDNATIVE-32xCPU-192GB 32 196608 0 51200 CLOUDNATIVE-32xCPU-256GB 32 262144 0 66560 CLOUDNATIVE-32xCPU-384GB 32 393216 0 76800 38xCPU-192GB 38 196608 2048 maxiops 24576 48xCPU-256GB 48 262144 2048 maxiops 24576 CLOUDNATIVE-48xCPU-384GB 48 393216 0 81920 CLOUDNATIVE-48xCPU-512GB 48 524288 0 92160 CLOUDNATIVE-64xCPU-192GB 64 196608 0 56320 CLOUDNATIVE-64xCPU-256GB 64 262144 0 71680 CLOUDNATIVE-64xCPU-384GB 64 393216 0 87040 64xCPU-384GB 64 393216 2048 maxiops 24576 CLOUDNATIVE-64xCPU-512GB 64 524288 0 97280 CLOUDNATIVE-80xCPU-512GB 80 524288 0 102400 80xCPU-512GB 80 524288 2048 maxiops 24576 High CPU Name Cores Memory Storage size Storage tier Transfer out (GiB/month) ──────────────────── ─────── ──────── ────────────── ────────────── ────────────────────────── HICPU-8xCPU-12GB 8 12288 100 maxiops 4096 HICPU-8xCPU-16GB 8 16384 200 maxiops 4096 HICPU-16xCPU-24GB 16 24576 100 maxiops 5120 HICPU-16xCPU-32GB 16 32768 200 maxiops 5120 HICPU-32xCPU-48GB 32 49152 200 maxiops 6144 HICPU-32xCPU-64GB 32 65536 300 maxiops 6144 HICPU-64xCPU-96GB 64 98304 200 maxiops 7168 HICPU-64xCPU-128GB 64 131072 300 maxiops 7168 High memory Name Cores Memory Storage size Storage tier Transfer out (GiB/month) ──────────────────── ─────── ──────── ────────────── ────────────── ────────────────────────── HIMEM-2xCPU-8GB 2 8192 100 maxiops 2048 HIMEM-2xCPU-16GB 2 16384 100 maxiops 2048 HIMEM-4xCPU-32GB 4 32768 100 maxiops 4096 HIMEM-4xCPU-64GB 4 65536 200 maxiops 4096 HIMEM-6xCPU-128GB 6 131072 300 maxiops 6144 HIMEM-8xCPU-192GB 8 196608 400 maxiops 8192 HIMEM-12xCPU-256GB 12 262144 500 maxiops 10240 HIMEM-16xCPU-384GB 16 393216 600 maxiops 12288 HIMEM-24xCPU-512GB 24 524288 700 maxiops 12288 Developer Name Cores Memory Storage size Storage tier Transfer out (GiB/month) ──────────────────── ─────── ──────── ────────────── ────────────── ────────────────────────── DEV-1xCPU-1GB-10GB 1 1024 10 standard 1024 DEV-1xCPU-1GB 1 1024 20 standard 1024 DEV-1xCPU-2GB 1 2048 30 standard 1536 DEV-1xCPU-4GB 1 4096 40 standard 2048 DEV-2xCPU-4GB 2 4096 60 standard 2560 DEV-2xCPU-8GB 2 8192 80 standard 3072 DEV-2xCPU-16GB 2 16384 100 standard 4096
For this tutorial, choose the first option in the Developer list (1 CPU core, 1 GB RAM, and 10 GB storage), named DEV-1xCPU-1GB-10GB.
DEV-1xCPU-1GB-10GB.
After you’ve decided on the server plan, it is time to choose the operating system for the server. UpCloud provides you with a few popular public templates to choose from, along with the option of a wider variety of distributions through CDROMs and the ability to download and install nearly any other possible operating system using custom images.
You can find a list of available templates here. There are lots of technical considerations, opinions, and personal/project preferences that need to be taken into account before making this choice. However, for this tutorial, you can select AlmaLinux 9 as it is a lightweight option compared to enterprise distributions of Linux.
Note: The commands used in this tutorial have been written with AlmaLinux in mind. If you choose to use a different OS, you might run into unexpected issues.
You will need to set up an SSH key pair to be able to remotely log into the server. You need to create an SSH key pair and provide upctl with its public key. You can follow this quick guide to generate the SSH key pair based on your local operating system.
You will need to provide the location of the public key file when running the upctl server create command.
upctl server create
Finally, you have the option to add an initialization script to the deployment.
Normally, right after you set up a server, you will want to do certain things on it before you start deploying your applications on it. These tasks can include anything from upgrading installed packages to configuring tools and setting up user accounts. Initialization scripts help you automate these tasks instead of having to manually do them after the server is deployed.
Since you will be deploying a Node.js application to this server, you need to ensure that Node is installed on it. You will also need the git CLI tool to interact with the repository and pull in the code. And, since the project uses yarn to manage dependencies and scripts, you will need to install it as well.
git
yarn
To have the server automatically do all of that after it is deployed, save the following script in a file named init-script.sh:
init-script.sh
#!/bin/bash sudo dnf update -y sudo dnf install curl dnf-plugins-core -y sudo dnf module install nodejs:22 -y sudo dnf install git -y npm install --global yarn
Remember to add the line #!/bin/bash to the top of the script to make sure the OS understands what kind of interpreter it needs to run this script. You will pass the location of this init-script.sh file in the server create command to have UpCloud run this script as soon as the server is deployed.
#!/bin/bash
server create
Now that you understand all of the configuration options for the server and have prepared the SSH key and the initialization script, here is the command you need to run to create the server where you’ll run your Node.js app.
upctl server create \ --title "Random Facts Generator Server" \ --zone sg-sin1 \ --os "AlmaLinux 9" \ --hostname random-facts-generator-server \ --ssh-keys id_rsa_gh.pub \ --plan DEV-1xCPU-1GB-10GB \ --user-data "$(cat init-script.sh)"
Here’s a quick explanation of the arguments and values used:
title
zone
os
hostname
ssh-keys
plan
user-data
init-script
cat
Once you run the command, you will receive a similar output:
✓ Creating server random-facts-generator-server 10 s UUID 00afeedb-f55a-4c2d-80ae-9298ac9120b9 IP Addresses 2a04:3543:1000:2310:78a8:8fff:feba:689f, 10.10.13.76, 213.163.197.191
You can run upctl server list to view the list of active servers along with their state:
upctl server list
✗ upctl server list UUID Hostname Plan Zone State ────────────────────────────────────── ─────────────────────────────── ──────────────────── ───────── ───────────── 00afeedb-f55a-4c2d-80ae-9298ac9120b9 random-facts-generator-server DEV-1xCPU-1GB-10GB sg-sin1 started
Once the state is started, you can SSH into the server using the command ssh root@<server-ip-address>. You can use upctl to retrieve the server IP address by running the command upctl server show <server-name>:
ssh root@<server-ip-address>.
upctl server show <server-name>
✗ upctl server show random-facts-generator-server Common UUID: 00afeedb-f55a-4c2d-80ae-9298ac9120b9 Hostname: random-facts-generator-server Title: Random Facts Generator Server Plan: DEV-1xCPU-1GB-10GB Zone: sg-sin1 State: started Simple Backup: no Licence: 0 Metadata: True Timezone: UTC Host ID: 4565254787 Server Group: Tags: Labels: No labels defined for this resource. Storage: (Flags: B = bootdisk, P = part of plan) UUID Title Type Address Size (GiB) Encrypted Flags ────────────────────────────────────── ────────────────────────────────── ────── ────────── ──────────── ─────────── ─────── 01a2d500-3374-438e-936e-ad43ea3aae32 random-facts-generator-server-OS disk virtio:0 10 no P NICs: (Flags: S = source IP filtering, B = bootable) # Type IP Address MAC Address Network Flags ─── ───────── ─────────────────────────────────────────────── ─────────────────── ────────────────────────────────────── ─────── 1 public IPv4: 213.163.197.191 7a:a8:8f:ba:72:9d 0376454f-48b5-4d43-8008-1755c3d792f0 S 2 utility IPv4: 10.10.13.76 7a:a8:8f:ba:99:23 03d31b4f-6fed-4ebc-947b-8973c008e3a4 S 3 public IPv6: 2a04:3543:1000:2310:78a8:8fff:feba:689f 7a:a8:8f:ba:68:9f 03000000-0000-4000-8030-000000000000 S
You’re now ready to deploy the application for the first time!
Before you start deploying the application, make sure you have forked it to your GitHub account.
Once ready, SSH into the server and run the following commands:
# Clone your forked repository git clone https://github.com/<your-github-username>/random-facts-generator.git # Change into the cloned directory cd random-facts-generator # Install dependencies yarn # Start the production server yarn start:prod
This will start the Node.js application in a background process on the server. The Express app is configured to run on port 5001, so you should now be able to see the deployed app in action on the web address http://<your-server-ip>:5001:
http://<your-server-ip>:5001
This indicates that your server and app have been deployed successfully! Now, it’s time to set up an automated pipeline that redeploys your app whenever you push a new commit to the main branch.
main
To create the pipeline, you will first need to set up Jenkins on a server. To do that, you’ll first create a new UpCloud server using the following command:
upctl server create \ --title "Jenkins Host" \ --zone sg-sin1 \ --os "AlmaLinux 9" \ --hostname jenkins-host \ --ssh-keys id_rsa_gh.pub \ --plan 1xCPU-2GB
This uses all the same options as the previous server create command, except for the server plan (this one uses the plan with 2GB RAM instead of 1GB) and the initialization script.
Once the server is deployed, SSH into it and run the following commands to install and start the Jenkins server:
sudo wget -O /etc/yum.repos.d/jenkins.repo \ https://pkg.jenkins.io/redhat-stable/jenkins.repo sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key sudo dnf upgrade # Add required dependencies for the jenkins package sudo dnf install fontconfig java-21-openjdk sudo dnf install jenkins sudo systemctl daemon-reload
Now, you need to configure the Jenkins server to start at machine boot, and manually start it once:
sudo systemctl enable jenkins sudo systemctl start jenkins
Now, you can go to the URL `http://<your-server-ip>:8080″ and set up your Jenkins server through the guided process. Make sure to install the community-recommended plugins (or at least the git plugin) and configure an admin user in the process.Furthermore, you will also need to install the NodeJS plugin to be able to run Node.js builds. To do that, head over to Dashboard > Manage Jenkins > Plugins and search and install the NodeJS plugin:
Once you have installed Node.js on the server, go to Dashboard > Manage Jenkins > Tools. Scroll to the bottom of the page and click the Add NodeJS button to set up the NodeJS installation:
In the new section that appears, name your installation “24” and make sure to set the latest version of Node.js in the Version dropdown. Once done, click on the Save button at the bottom of the page:
Once you’ve finished setting up the Jenkins server, you can start creating the pipeline.
Log in to your Jenkins admin dashboard, and either click on the + New Item option from the left navigation pane or the Create new job button in the middle of the page:
In the New Item page, select Pipeline as item type and enter a name for the pipeline. Once done, click on the OK button.
You will now need to configure the pipeline. First of all, check the Github project option in the General section and paste the URL of your forked GitHub repository:
Next, scroll below to the Triggers section and check the GitHub hook trigger for GITScm polling option:
This means that the pipeline will be triggered whenever Jenkins receives a GitHub push hook for this repository. To make this work, you will need to configure the GitHub plugin to receive hooks from your GitHub account.
push
To do that, follow either the manual setup or the automated setup instructions in this guide by Jenkins. Make sure to configure the GitHub plugin correctly before moving ahead.
A quick method for now would be to go to Dashboard > Manage Jenkins > System and copy the hook URL from the ? tooltip next to the GitHub Servers section and add it to your Github repo’s settings > Webhooks.
Once done, scroll down to the Pipeline section in the pipeline configuration page and paste the following script in the Script textbox:
pipeline { agent any tools { nodejs '24' } environment { SERVER_IP = '<your-server-ip-here>' UPCLOUD_USERNAME = 'root' } stages { stage('Checkout') { steps { checkout scmGit( branches: [[name: 'main']], userRemoteConfigs: [[url: 'https://github.com/krharsh17/random-facts-generator.git']] ) } } stage('Install Dependencies') { steps { sh 'npx yarn' } } stage('Deploy') { steps { withCredentials([sshUserPrivateKey(credentialsId: 'deploy-key', keyFileVariable: 'DEPLOY_KEY')]) { sh ''' # Start SSH agent eval $(ssh-agent -s) # Set proper permissions and add key chmod 400 $DEPLOY_KEY ssh-add $DEPLOY_KEY # Deploy to server ssh -o StrictHostKeyChecking=no $UPCLOUD_USERNAME@$SERVER_IP /bin/bash << 'EOT' cd /random-facts-generator git pull origin main yarn restart:prod EOT ''' } } } } post { always { cleanWs() } success { echo 'Pipeline completed successfully!' } failure { echo 'Pipeline failed!' } } }
Once done, click on the Save button at the bottom of the page.
Here’s a quick explanation of the Jenkinsfile:
SERVER_IP
UPCLOUD_USERNAME
checkout scmGit(...)
checkout scm
npx yarn
deploy-key
restart:prod
always
success
failure
Before you can run this pipeline, you need to configure the deploy key as a secure credential in the Jenkins server.
Jenkins offers a more convenient and structured way to handle credentials, and especially SSH keys. To provide your SSH key to Jenkins, go to Dashboard > Manage Jenkins > Credentials and click on System under the Stores scoped to Jenkins:
On the next page that opens, click on the Global credentials (unrestricted) domain in the list. In production settings, you should choose to create a separate domain for your project to further implement abstraction:
Here, click on the + Add Credentials button at the top right.
On the New credentials page, set:
Once done, click the Create button at the bottom:
This will add the private key to the global scope of your Jenkins instance. This means that you can now access it in the pipeline and connect to your UpCloud server from the pipeline environment.
The pipeline is now set up and listening for new commits pushed to your repo. To test it out, you can try updating something in the repo, such as the footer text in the public/index.html file that says “Made in 2024” to change it to “Made in 2025”. You will see that a new build gets triggered automatically:
Within a minute, you will see the build logs end with a SUCCESS message:
SUCCESS
And in a minute or two, the text on your public website will be updated:
This means that your pipeline has been set up and connected to your UpCloud server successfully! This marks the end of the tutorial.
Setting up SSH keys and cloud scripts can sometimes be confusing. Here are a few common problems you might see, along with easy ways to fix them:
Host key verification failed
-o StrictHostKeyChecking=no option
ssh
sh
Error loading key "<key-file-name": error in libcrypto
-----BEGIN OPENSSH PRIVATE KEY-----
chmod 400
Permission denied (publickey)
ssh-add $DEPLOY_KEY
kex_exchange_identification: read: Connection reset by peer
Connection reset by port 22:
When deploying to a freshly provisioned server using a cloud-init script, some commands may fail silently. This could be due to missing -y flags (which skip interactive prompts), unavailable package versions, or temporary DNS issues. To debug such failures, you’ll need to check the logs from when the script ran. You can do this by logging into the server and running sudo grep cloud-init /var/log/messages.
-y
sudo grep cloud-init /var/log/messages.
Setting up Jenkins to deploy your Node.js application to UpCloud is a powerful way to automate your development workflow. Jenkins handles everything from dependency installation to testing and deployment with every push, saving time and reducing manual errors. This kind of automation is especially helpful for solo developers and small teams who want to maintain high development velocity without compromising on code quality.
UpCloud makes a great foundation for this setup, offering fast and reliable cloud servers that can easily run both your application servers and your CI infrastructure. Whether you’re hosting your production app, running Jenkins agents, or doing both on the same account, UpCloud’s flexible compute options make it easy to scale resources as needed. With features like Hot Resize, you can add CPU or memory to your servers without downtime, ensuring smooth growth as your apps and CI pipelines become more demanding.
Ready to automate your deployments and scale with confidence? Sign up for UpCloud to launch your first server in minutes. Then connect your Jenkins pipeline using the Jenkinsfile from this guide and stay focused on shipping code, while UpCloud keeps your infrastructure fast, stable, and ready to grow.
Your email address will not be published. Required fields are marked *
Comment *
Name *
Email *
Website
Save my name, email, and website in this browser for the next time I comment.
Δ
See all tutorials