In this tutorial, we'll setup a CD Pipeline for a Website on Ubuntu 24.04.
In today’s fast-paced development environment, having a reliable Continuous Deployment (CD) pipeline allows us to deliver updates to our website rapidly and confidently. In this guide, we’ll walk through setting up a CD pipeline for a simple static or dynamic website on an Ubuntu server.
We’ll leverage Git for version control, GitHub Actions for our Continuous Integration (CI), and an automated deployment script on the server to pull changes and restart services as needed. By the end, our website updates will flow seamlessly from code commit to live production with minimal manual intervention.
Prerequisites
Before we begin, let’s ensure we have the following in place:
- A Ubuntu 24.04 dedicated server or KVM VPS.
- A public or private GitHub repository containing your website’s source code.
- An SSH key generated on your local machine, with the public key added to your GitHub account for cloning private repos.
- Basic Shell Knowledge.
Setup a CD Pipeline for a Website on Ubuntu
1. Prepare the Ubuntu Server
Update packages
sudo apt update && sudo apt upgrade -y
Keeping the system updated ensures we have the latest security patches and software features.
Install Git and other essentials
sudo apt install -y git curl build-essential
These tools will help us clone repositories and build any frontend assets.
Create a Deployment User
sudo adduser deployer
sudo usermod -aG sudo deployer
Running deployments under a dedicated user improves security by limiting access.
Set Up SSH Access
Switch to the new user:
sudo su - deployer
Create an .ssh
directory and add your public key:
mkdir ~/.ssh && chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
Paste your public key, save, then:
chmod 600 ~/.ssh/authorized_keys
2. Clone the Website Repository
Generate a Deploy Script Directory
mkdir ~/site && cd ~/site
Clone from GitHub
git clone git@github.com:your-org/your-website.git .
Test a Local Build (if applicable)
If you’re using a static site generator or Node.js:
# Example for a Node.js build
npm install
npm run build
Confirm that the generated files appear (e.g., in dist/
or public/
).
3. Create a Deployment Script
We’ll write a Bash script that pulls the latest code and restarts our web service.
Create deploy.sh
nano ~/site/deploy.sh
Populate with the following:
#!/usr/bin/env bash
set -e
echo "🔄 Starting deployment at $(date)"
# Navigate to site directory
cd /home/deployer/site
# Fetch and reset to latest main branch
git fetch origin main
git reset --hard origin/main
# Install dependencies & build (if needed)
if [ -f package.json ]; then
npm ci
npm run build
fi
# Restart the web server (example using systemd)
sudo systemctl restart site.service
echo "✅ Deployment completed at $(date)"
Make it executable
chmod +x ~/site/deploy.sh
4. Configure the Web Service
Assuming we’re serving via a simple Node.js or static file server under systemd:
Create a systemd Service
sudo nano /etc/systemd/system/site.service
Example for a Node.js Express App:
[Unit]
Description=Our Simple Website
After=network.target
[Service]
Type=simple
User=deployer
WorkingDirectory=/home/deployer/site
ExecStart=/usr/bin/node server.js
Restart=on-failure
[Install]
WantedBy=multi-user.target
Enable and Start
sudo systemctl daemon-reload
sudo systemctl enable site.service
sudo systemctl start site.service
Verify
sudo systemctl status site.service
Ensure the service is active and listening (you can also test via curl localhost).
5. Set Up GitHub Actions for CI/CD
We’ll trigger our deploy.sh
on the server whenever code is merged into main.
Add a Workflow File
In your repository, create .github/workflows/deploy.yml
.
Populate with:
name: CI/CD Pipeline
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Run tests (optional)
run: |
# Add your test commands here
echo "Running tests..."
- name: Deploy to Ubuntu server
uses: appleboy/ssh-action@v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: deployer
key: ${{ secrets.SERVER_SSH_KEY }}
port: 22
script: |
cd /home/deployer/site
./deploy.sh
Configure GitHub Secrets
In your repo’s Settings → Secrets:
- SERVER_HOST: your server’s IP or domain
- SERVER_SSH_KEY: the private SSH key (matched to the public key added earlier)
6. Test the Pipeline
Push a Change
echo "<!-- Deployed at $(date) -->" >> index.html
git add index.html
git commit -m "Test CD pipeline"
git push origin main
Monitor GitHub Actions
Navigate to the Actions tab and watch the workflow run.
Verify on the server. SSH into the server:
ssh deployer@your-server
tail -n 20 /home/deployer/site/deploy.log
Or simply reload the website in a browser and see your timestamped comment.
7. Enhance and Secure
- Rollback Strateg: Keep a copy of the previous release (e.g., Git tags) to revert quickly if something breaks.
- SSL with Let’s Encrypt: Install Certbot and configure HTTPS to secure traffic:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d example.com
Monitoring & Alerts: Integrate basic uptime monitoring (e.g., UptimeRobot) and log shipping (e.g., using Promtail + Grafana Loki).
Conclusion
In this tutorial, we've setup a CD Pipeline for a Website on Ubuntu 24.04. By following these steps, we’ve built a robust Continuous Deployment pipeline where each commit to main automatically triggers a secure SSH connection to our Ubuntu server, pulls the latest code, builds the project, and restarts our service. This setup empowers us to focus on writing features instead of manual deployments, driving higher efficiency and reliability in our web development workflow.