Use GitHub Actions to Automate Your CI/CD for React and Node.js Applications on Ubuntu
Tags: githubactions, react, node, cicd
Published: 2023-05-18 09:42:19

## Introduction:

Continuous Integration and Continuous Deployment (CI/CD) have become crucial aspects of modern software development. By automating the build, testing, and deployment processes, developers can save time, reduce errors, and deliver high-quality applications. GitHub Actions, a powerful feature provided by GitHub, allows developers to automate these processes easily. In this article, we will explore how to set up GitHub Actions for CI/CD of React and Node.js applications on an Ubuntu environment.

## Prerequisites:

Before diving into setting up GitHub Actions, ensure that you have the following:

- A GitHub account with a repository for your React or Node.js application.
- A basic understanding of Git and GitHub workflows.
- An Ubuntu-based machine or a virtual machine to run the CI/CD pipeline.

## Setting Up the Environment:

1. Start by creating a new directory on your Ubuntu machine to store the necessary files for the CI/CD pipeline.
2. Install Node.js and npm (Node Package Manager) if they are not already installed. You can do this by running the following command:

```shell
sudo apt update
sudo apt install nodejs npm
```


## Configuring GitHub Actions:

1. Navigate to your GitHub repository and click on the "Actions" tab.
2. Click on the "Set up a workflow yourself" button to create a new workflow file.
3. Choose a name for the file, such as ci-cd.yml, and update the contents as follows:
```YAML
# This workflow is a Continuous Integration/Continuous Deployment (CI/CD) pipeline for deploying a Node.js backend application
# to a remote ubuntu server.
#
# Here are some comments to make it easier for everyone to use:
#
# 1. The workflow uses environment variables to set the application name, component name, and release path.
#    Ensure that these are set correctly according to your application's configuration.
#
# 2. The workflow runs on a push to the main branch and can be manually triggered with inputs to specify the target environment.
#
# 3. It's important to note that this workflow uses several secrets that need to be set up
#    in order for it to work properly. You will need to create the following secrets in your repository settings:
#
#    3.1. REMOTE_SERVER: the IP address or domain name of the remote server you are deploying to.
#    3.2. REMOTE_USER: the username you use to SSH into the remote server (root user is recommended).
#    3.3. REMOTE_KEY: the SSH private key you use to authenticate with the remote server.
#    3.4. ENV_FILE: the contents of your application's .env file. This should be a single-line string with each
#         environment variable separated by spaces.
#    3.5. NGINX_CONFIG: the contents of your NGINX configuration file. This should be a multi-line string with each line
#         separated by a newline character.
#
# Overall, this workflow provides a good starting point for deploying a Node.js backend application to a remote server using GitHub Actions.
# However, it should be customized according to your application's specific requirements.

name: 'CI/CD'

env:
  APP_NAME: 'node'
  COMPONENT_NAME: 'backend'
  RELEASE_PATH: /root/node/backend

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      # The first step checks out the code from the repository.
      - name: Checkout code
        uses: actions/checkout@v2

      # The second step sets up Node.js with version 16.
      - name: Setup Node.js
        uses: actions/setup-node@v2
        with:
          node-version: 16

      # The third step transfers the code to the remote server using the Secure Copy (SCP) protocol.
      # The source directory is set to .,!./uploads, which excludes the uploads directory from being transferred.
      # Ensure that this is set correctly according to your application's file structure.
      - name: Transfer files to server
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.REMOTE_SERVER }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.REMOTE_KEY }}
          rm: true
          source: '.,!./uploads'
          target: ${{ env.RELEASE_PATH }}/build

      # The fourth step creates shared folders for the uploads directory and the node_modules directory and creates symbolic links
      # to these folders in the current release directory. This helps to ensure that the uploads and node_modules directories
      # persist across releases and are not overwritten.
      - name: Create shared folders
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.REMOTE_SERVER }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.REMOTE_KEY }}
          script: |
            cd ${{ env.RELEASE_PATH }}
            mkdir -p shared/uploads
            mkdir -p shared/node_modules
            ln -sfn ${{ env.RELEASE_PATH }}/shared/uploads ${{ env.RELEASE_PATH }}/build/uploads
            ln -sfn ${{ env.RELEASE_PATH }}/shared/node_modules ${{ env.RELEASE_PATH }}/build/node_modules

      # The fifth step copies configuration files to the remote server, including the .env file and an NGINX configuration file.
      # The NGINX configuration file is used to proxy requests to the Node.js backend application.
      # Ensure that this is set correctly according to your application and server's configuration.
      - name: Copy config files
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.REMOTE_SERVER }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.REMOTE_KEY }}
          script: |
            echo '${{ secrets.ENV_FILE }}' > ${{ env.RELEASE_PATH }}/build/.env
            echo '${{ vars.NGINX_CONFIG }}' > ${{ env.RELEASE_PATH }}/build/nginx.conf
            sudo systemctl restart nginx

      # The sixth step installs dependencies, builds the application.
      - name: Install dependencies
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.REMOTE_SERVER }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.REMOTE_KEY }}
          script: |
            cd ${{ env.RELEASE_PATH }}/build
            yarn install
            yarn run build

      # The seventh step starts it with PM2.
      # PM2 is a process manager for Node.js applications that helps to ensure that the application runs continuously
      # and can be easily managed. Ensure that this is set correctly according to your application's dependencies and build process.
      - name: Start PM2
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.REMOTE_SERVER }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.REMOTE_KEY }}
          script: |
            cd ${{ env.RELEASE_PATH }}/build
            pm2 delete -s ${{ env.APP_NAME }} || :
            pm2 start dist/index.js --name "${{ env.APP_NAME }}"
```
4. In the above configuration, we set up the sample workflow for Node.js/Express to trigger on pushes to the `main` branch.
5. The `build` job checks out the repository, sets up Node.js version 16, transfer files to the server, installs dependencies, creates the build and restart PM2 service.
6. You can add/modify deployment commands in the steps to deploy your application to a hosting provider like Heroku, Netlify, or AWS.

## Running the CI/CD Pipeline:

1. Commit and push the `ci-cd.yml` file to your GitHub repository.
2. GitHub Actions will automatically detect the new workflow and start the CI/CD pipeline.
3. You can monitor the progress of the pipeline in the "Actions" tab of your repository.
4. If any errors occur during the build or test stages, GitHub Actions will provide detailed logs to help you identify and resolve issues.

## Conclusion:

GitHub Actions offers a convenient way to automate your CI/CD pipeline for React and Node.js applications. By leveraging the power of workflows, you can save time and effort while maintaining the quality of your codebase. In this article, we explored how to set up a basic CI/CD workflow using GitHub Actions on an Ubuntu environment. Feel free to customize the workflow to suit your specific needs and take advantage of the rich ecosystem of GitHub Actions to enhance your development process further.

Happy automating!