CI/CD Deployment on Ubuntu VPS Using GitHub Actions
Implementing Continuous Integration and Continuous Deployment (CI/CD) is crucial for maintaining a streamlined and efficient development workflow. In this guide, we will explore how to set up CI/CD on an Ubuntu VPS using SSH for deploying a Next.js project with GitHub Actions.
Why CI/CD is Crucial for Modern Development
Enhancing Development Efficiency
CI/CD automates the testing and deployment processes, which significantly reduces the time and effort required to deliver high-quality software. By continuously integrating code changes and automatically deploying them to production, development teams can ensure that their applications are always in a deployable state.
Improving Code Quality and Consistency
Automated testing and integration help identify issues early in the development cycle, ensuring that only code that passes predefined quality checks is deployed. This consistency leads to more stable and reliable applications, reducing the risk of bugs and errors in production.
My Journey to CI/CD Implementation
I decided to write this article to share my experience in setting up a CI/CD pipeline for a Next.js project. After facing challenges with manual deployments and inconsistent build processes, I realized the need for a robust solution to streamline these tasks. GitHub Actions provided an integrated platform to automate the entire workflow, from code changes to deployment on an Ubuntu VPS.
Prerequisites
Tools and Technologies
- Ubuntu VPS: Ensure you have an Ubuntu server set up.
- SSH Access: Secure Shell access to your VPS.
- GitHub Repository: Your project hosted on GitHub.
- Next.js Project: Example project for deployment.
Setup Your Environment
- Install Node.js and npm: Required for Node.js project
- Install pm2: Monitoring Project
- Install Git: Version control system.
Step-by-Step Guide
1. Setting Up SSH Keys in VPS
- Generate SSH Key Pair:
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
- Setup SSH Key for authorization: Copy generated public key content to
.ssh/authorized_keys
- GitHub Secrets: You should create your GitHub secrets for your repository. Go to your repository > Settings > Secrets > Actions > New repository secret.
- Create GitHub Secrets
Here are required Github Secrets
PERSONAL_GITHUB_TOKEN=Your GitHub Token to pull your repo.
VPS_IP=Your Ubuntu Server IP (Or you can input the domain instead of IP)
VPS_USERNAME=Your username to login to your Server (e.g. ubuntu)
SSH_PRIVATE_KEY=Past your SSH private key that you generated in the server
SSH_PASSPHRASE=Your password to login to your Server
- Create GitHub Vars
Create MY_APP=(your product website link)
2. Configuring GitHub Actions
- Create Workflow File:
.github/workflows/deploy.yml
- Define Workflow Triggers: Specify when the workflow should run (e.g., on push to main branch).
- Setup SSH connection using actions/checkout@v2
name: Auto Deploy in VPS after Push in Production
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy project
permissions:
deployments: write
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: 'actions/checkout@v2'
with:
ref: main
token: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
- name: Create GitHub deployment
uses: chrnorm/deployment-action@v2
id: deployment
with:
token: '${{ github.token }}'
environment-url: ${{ vars.MY_APP }}
environment: production
- name: Set up SSH Key and Deploy my App on Server
# run: |
uses: appleboy/ssh-action@master
env:
GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
with:
host: ${{ secrets.VPS_IP }}
username: ${{ secrets.VPS_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
passphrase: ${{ secrets.SSH_PASSPHRASE }}
port: 22
script: |
git config --global url."https://${{ secrets.PERSONAL_GITHUB_TOKEN }}:@github.com".insteadOf "https://github.com"
cd chatg/
git pull origin main
npm ci
npm run frontend
pm2 restart chatg --update-env
- Add code to show the environment status.
- name: Update deployment Status (success)
if: success()
uses: chrnorm/deployment-status@v2
with:
token: '${{ github.token }}'
environment-url: ${{ vars.MY_APP }}
state: 'success'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Update deployment status (failure)
if: failure()
uses: chrnorm/deployment-status@v2
with:
token: '${{ github.token }}'
environment-url: ${{ vars.MY_APP }}
state: 'failure'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
This is example full code to deploy on main branch with production environment.
name: Auto Deploy in VPS after Push in Production
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy project with Nginx
permissions:
deployments: write
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: 'actions/checkout@v2'
with:
ref: main
token: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
- name: Create GitHub deployment
uses: chrnorm/deployment-action@v2
id: deployment
with:
token: '${{ github.token }}'
environment-url: ${{ vars.MY_APP }}
environment: production
- name: Set up SSH Key and Deploy my App on Server
# run: |
uses: appleboy/ssh-action@master
env:
GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
with:
host: ${{ secrets.VPS_IP }}
username: ${{ secrets.VPS_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
passphrase: ${{ secrets.SSH_PASSPHRASE }}
port: 22
script: |
git config --global url."https://${{ secrets.PERSONAL_GITHUB_TOKEN }}:@github.com".insteadOf "https://github.com"
cd chatg/
git pull origin dev-branch
npm ci
npm run frontend
pm2 restart chatg --update-env
- name: Update deployment Status (success)
if: success()
uses: chrnorm/deployment-status@v2
with:
token: '${{ github.token }}'
environment-url: ${{ vars.MY_APP }}
state: 'success'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Update deployment status (failure)
if: failure()
uses: chrnorm/deployment-status@v2
with:
token: '${{ github.token }}'
environment-url: ${{ vars.MY_APP }}
state: 'failure'
deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- Deploy to VPS: try to commit and push to your main branch with updated project
Conclusion
Benefits of CI/CD with GitHub Actions
- Automation: Reduces manual intervention.
- Reliability: Ensures consistent and reliable deployments.
- Speed: Faster development cycles and quicker releases.
Next Steps
- Monitor Your Deployments: Set up monitoring and alerts.
- Enhance Security: Regularly update your dependencies and server.
- Optimize Performance: Continuously improve your build and deployment processes.
By following this guide, you will have a robust CI/CD pipeline set up on your Ubuntu VPS, making your Next.js project deployments smoother and more efficient. Happy coding!