Setting Up Continuous Deployment for Node.js Applicaitons on Ubuntu

In this blog post, we will explore how to set up Continuous Deployment (CD) for a Node.js application using GitHub Actions.

Prerequisites

  • A basic understanding of Git, GitHub, and Linux commands.
  • A GitHub account and a repository.
  • An Ubuntu server instance.

Understanding SSH Key.

Before diving into this blog, it's important to have a basic understanding of SSH keys and how they are used. If you're new to this concept, I highly recommend referring to this detailed blog post SSH Keys: A Beginner's Guide (zysk.tech) for a thorough understanding. Even if you're familiar with SSH keys, a quick refresher can be immensely helpful. So, take a moment to read up on SSH keys - it'll make the rest of this guide much clearer and more beneficial.

Adding Public key to GitHub

To clone your repository and pull code without needing to enter a password, you can add your public SSH key to GitHub. First, copy your public key using the following command:

cat ~/.ssh/id_ed25519.pub

Then, click this link to navigate to the SSH and GPG keys page on GitHub. Once logged in, click New SSH Key give your key a title in the provided field, paste your copied public key into the Key field, and then click Add SSH Key. This will allow you to authenticate to GitHub securely without a password.

Adding Public Key to the authorized_keys File

As we have understood above, to enable SSH connections to this server, you must add your public key to the authorized_keys file.

Begin by navigating to the .ssh folder with the command:

cd ~/.ssh

Next, open or create the authorized_keys file using:

sudo nano authorized_keys
Note: this command will also create the file if it does not already exist.

Paste your public key into this file to allow access.

Creating GitHub Workflow

With the basic setup complete, we’re ready to begin implementing Continuous Deployment. Start by opening your application’s root directory. Here, you’ll need to create a specific directory structure for GitHub Actions:

  1. Create a new folder named .github, if it doesn't already exist.
  2. Inside the .github folder, create another folder named workflows.
  3. Within the workflows folder, create a file and name it deploy.yml (you can choose a different name if you prefer, but ensure it ends with .yml).

This deploy.yml file will contain the YAML script for your deployment workflow, defining the actions that GitHub will perform automatically every time you push changes to your repository.

here is a script for deploying a Monolithic Nestjs applicaiton

name: Integration Build & Deploy

on:
  push:
    branches: [BRANCH-NAME] # Replace BRANCH-NAME with the name of your branch

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy NodeJS app
        uses: appleboy/ssh-action@v0.1.2
        with:
          host: ${{secrets.SSH_HOST}}
          key: ${{secrets.SSH_KEY}}
          username: ${{secrets.SSH_USERNAME}}
          script: |
            cd <APPLICATION_FOLDER_NAME> # Replace with the name of your application's directory
            git checkout BRANCH-NAME # Ensure this matches the branch name above
            git pull origin BRANCH-NAME # Ensure this matches the branch name above
            echo 'Code is successfully pulled from the repository!'
            if [ ${{secrets.UPDATE_NODE_MODULES}} == 'true' ]; then
              echo 'Updating node modules...'
              npm install
              echo 'Node modules are successfully updated!'
            fi
            pm2 stop 0 # Replace 0 with your pm2 instance id
            echo 'All running processes are successfully stopped!'
            npm run build
            echo 'Build is successfully completed!'
            pm2 restart 0 # Replace 0 with your pm2 instance id
            echo 'All processes are successfully restarted!'

Explanation of the Script:

  1. Trigger: This workflow is triggered on pushes to the specified branch.
  2. Job Setup: The job runs on the latest Ubuntu virtual environment provided by GitHub.
  3. Deployment Steps: The steps use appleboy/ssh-action@v0.1.2 for SSH access. It allows the workflow to SSH into your server using credentials defined in GitHub secrets (SSH_HOST, SSH_KEY, SSH_USERNAME).
  4. Script Execution:
  • The script navigates to your application’s directory, updates it from the specified branch.
  • It conditionally updates Node modules if a secret (UPDATE_NODE_MODULES) is set to 'true'.
  • Uses pm2 to stop and restart the application processes, ensuring zero downtime.
  • Completes by building and restarting the application.

This setup ensures that your application is automatically pulled, built, and restarted on your server whenever changes are made to the branch you specify.

Note: Adjust the placeholders and secrets according to your actual setup.
Note: In this setup pm2 will not work if you have installed node using nvm please make sure that you have installed node directly

Adding New Repository Secrets to GitHub

  1. Go to your GitHub repository where you want to add secrets.
  2. Select Settings option on the top bar
  3. In the left sidebar of your repository’s settings page, click on Secrets and variables. This will expand a dropdown menu.
  4. From the dropdown menu, select Actions under the Repository secrets section.
  5. Click New repository secret to create a new secret, enter a name for your secret in the Name field, Paste the value of the secret into the Secret field. Click Add secret to save your new repository secret.

Secrets for the Workflow

Now we understood how to add secrets to the GitHub let's start adding secrets to our workflow.

  • SSH_HOST add the public IP of the instance.
  • SSH_USERNAME username of the instance. you can find it out with the following command whoami
  • SSH_KEY private key of the instance.
  • UPDATE_NODE_MODULES set true when you wanted to run the npm i command.

Once you have configured your GitHub Actions workflow and added all necessary secrets, pushing code to the specified branch in your repository will automatically trigger the workflow. Here’s how you can monitor the deployment process:

  1. Push Your Code: Commit your changes and push them to the branch that is monitored by your GitHub Actions workflow. This action will initiate the deployment process defined in your .yml file.
  2. Check the Workflow Status:
  • To see the status of the deployment, go to your GitHub repository and click on the Actions tab. This tab is located at the top of your repository page.
  • Inside the Actions tab, you will find a list of all the workflow runs. Click on a specific run to view detailed information, including each step’s success or failure, logs, and the duration of the process.

By following these steps, you can ensure that your Node.js application is continuously deployed smoothly and keep track of each deployment’s progress directly within GitHub.