Skip to content

Automating App Deployment on a VPS with GitHub Actions

Published: at 03:47 AM in 8 min readSuggest Changes

Introduction

In today’s fast-paced development environment, automating the deployment process is crucial for maintaining efficiency and reliability. GitHub Actions provides a powerful platform for automating workflows, including deployment to Virtual Private Servers (VPS). In this article, we will explore how to set up GitHub Actions to automate your VPS deployment process, ensuring a seamless CI/CD experience.

While this method can be applied to various VPS providers and various software stacks, we will focus on a common scenario: deploying a Next.js application to a VPS running Ubuntu.

Prerequisites

Before we dive into the setup, ensure you have the following:

  1. A VPS running Ubuntu (or any other Linux distribution).
  2. SSH access to your VPS.
  3. A GitHub repository containing your Next.js application.
  4. A domain name pointing to your VPS (optional but recommended).

Step 1: Setting Up Your VPS

First, you need to prepare your VPS for deployment. Connect to your VPS via SSH:

ssh user@your-vps-ip

Once connected, update your package list and install Node.js and npm. We recommend using Node Version Manager (nvm) for managing Node.js versions:

# Step 1: Update the system
sudo apt update && sudo apt upgrade -y

# Step 2: Install prerequisites
sudo apt install curl build-essential libssl-dev -y

# Step 3: Install nvm
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

# Load nvm
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"

# Step 4: Install the latest version of node
nvm install node

# Step 5: Check the installed versions
echo "Node version:"
node -v
echo "NPM version:"
npm -v

# Finish
echo "Installation completed!"

# Step 6: Install LTS version of node
nvm install --lts
nvm use --lts

The above commands will install the latest version of Node.js and npm. You may also want to install pm2, a process manager for Node.js applications:

sudo npm install -g pm2

pm2 will help you manage your application processes and keep them running in the background, restarting them if they crash.

Step 2: Configuring Your GitHub Repository

2.1: Adding Secrets

To securely connect to your VPS from GitHub Actions, you need to add your VPS credentials as secrets in your GitHub repository. Go to your repository on GitHub, click on Settings, then Secrets and variables, and finally Actions. Here, you will add the following secrets:

If you don’t already have an SSH key, you can generate one using the following command:

cd ~/.ssh
ssh-keygen -t rsa -b 4096 -C "youremailaddress"

You’ll be prompted to name your key. Let’s call it github_action and you can leave the passphrase empty.

In order to copy the private key to your GitHub secrets, run the following command:

cat github_action

Copy the output and paste it into the SSH_PRIVATE_KEY secret in your GitHub repository. Make sure to keep your private key secure and never share it publicly. Add the other GitHub secrets as well.

2.2: Adding the Public Key to Your VPS

After generating the key, you need to add the public key to your VPS’s ~/.ssh/authorized_keys file:

cd ~/.ssh
cat github_action.pub >> authorized_keys

This command appends your public key to the list of authorized keys on your server, granting access for automated deployments.

Step 3: Creating the GitHub Actions Workflow

Create a GitHub Actions workflow by adding an action YAML file inside the .github/workflows directory in your repository. You can name it deploy.yml. In this file, you will define the steps for your deployment process. Namely, on an event such as pushing to the main branch, the workflow will build your application and deploy it to your VPS.

Here’s a sample workflow configuration:

name: Deployment Workflow

# Trigger this workflow on pushes to the specified branch
on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Install dependencies
        run: npm install

      - name: Build Next.js app
        run: npm run build

      - name: SSH Deploy
        # Use the 'appleboy/ssh-action' action for SSH deployment
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }} # Your server's IP address
          username: ${{ secrets.USERNAME }} # Your server's username
          key: ${{ secrets.SSH_PRIVATE_KEY }} # Your server's SSH private key
          script: |
            export NVM_DIR="$HOME/.nvm"
            [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
            cd ${{ secrets.APP_DIR }} # Specify the path to your app directory on the server
            git pull
            npm install
            npm run build
            pm2 restart {service_name} # Replace with your PM2 service name

Note: Make sure to replace {service_name} with the actual name of your PM2 service. In the script section, you can customize the commands to fit your deployment needs. You’ll notice that we are running the nvm.sh script to load nvm before executing any Node.js commands. This is necessary due to the way the listed ssh-action runs commands in a non-interactive shell, which does not load the user’s profile. Thus, nvm will not be available unless we explicitly load it.

Step 5: Setting Up PM2

To ensure your application runs continuously, you can set it up with PM2. To run your application with PM2, navigate to your application directory and run:

pm2 start npm --name "nextjs" -- start

where "nextjs" is the name you want to give your PM2 process. You can provide additional options as needed:

pm2 start npm --name "nextjs" -- start -- --port 3000

Finally, You can also set it to restart automatically on server reboots:

pm2 startup
pm2 save

The commands above will generate a startup script and save the current process list, ensuring that your application starts automatically when the server reboots.

Now that we have our application running with PM2, let’s explore how to handle errors, set up monitoring, and troubleshoot common issues in the following sections.

Error Handling and Rollback Strategies

When automating deployments, it’s crucial to have a plan for when things go wrong. Here are some strategies to handle errors and rollback if necessary:

1. Use PM2 for Zero-Downtime Deployments

PM2 supports zero-downtime reloads, which can help minimize the impact of a failed deployment:

pm2 reload {service_name}

2. Implement Version Tagging

Before each deployment, tag your Git commit with a version number:

git tag -a v1.0.0 -m "Version 1.0.0"
git push origin v1.0.0

If a deployment fails, you can easily rollback to a previous version:

git checkout v0.9.9
pm2 reload {service_name}

Monitoring and Logging

Monitoring your deployed application is crucial for maintaining its health and performance. Here are some basic steps to set up monitoring and logging:

1. PM2 Monitoring

PM2 provides built-in monitoring capabilities. You can view basic metrics with:

pm2 monit

For more detailed monitoring, consider setting up PM2 Plus, which offers a web-based dashboard.

2. Application Logs

PM2 also manages your application logs. View your application logs with:

pm2 logs {service_name}

To set up log rotation and prevent your logs from consuming too much disk space, use:

pm2 install pm2-logrotate

Troubleshooting

Here are some common issues you might encounter during setup or deployment, and how to resolve them:

1. SSH Connection Issues

If GitHub Actions can’t connect to your VPS, check the following:

2. Node.js Version Mismatch

If you encounter Node.js version-related errors, make sure that:

3. PM2 Process Not Found

If PM2 can’t find your process during restart, it might be because the process name has changed. You can list all PM2 processes with:

pm2 list

Then, update your deployment script with the correct process name.

4. Build Failures

If your build fails during deployment:

Remember, when troubleshooting, the GitHub Actions logs and your application logs on the VPS are your best friends. Always check these first when something goes wrong.

Conclusion

Automating your VPS deployment process with GitHub Actions can significantly streamline your workflow, reduce human error, and ensure consistent deployments. By following the steps outlined in this guide, you’ve set up a robust CI/CD pipeline that automatically builds and deploys your Next.js application to your VPS whenever you push changes to your main branch.

This setup not only saves time but also allows for rapid iteration and seamless collaboration among team members. With the power of GitHub Actions and the flexibility of VPS hosting, you can focus more on developing features and less on the intricacies of deployment.

Remember, while this guide focused on deploying a Next.js application to an Ubuntu VPS, the principles can be adapted for various tech stacks and hosting environments. As you become more comfortable with this workflow, consider exploring additional features like running automated tests before deployment or setting up staging environments.

By embracing automation in your deployment process, you’re taking a significant step towards more efficient and reliable software development practices. Happy coding and deploying!


Previous Post
Byte Pair Encoding Tokenizer
Next Post
Tensor Puzzles