Prerequisites

You will need a server (AWS, GCP, Azure, etc.) running. Make sure the DNS is configured before starting.

Overview

We’re going to add a workflow to the repository as a continuous deployment pipeline. In other words, whenever you push to Github’s main branch, the workflow is going to run and automatically upload the repository onto the server and start the container.

Creating the workflow file

In the root directory, create a file under .github/workflows: main.yml (honestly any name works).

# This is a basic workflow to help you get started with Actions

name: Deploy to server

# Controls when the action will run.
on:
  # Triggers the workflow on a push to the main branch
  push:
    branches: [main]
  # Allow manual trigger
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  deploy:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      # <https://stackoverflow.com/a/61236896>
      - name: Tar repository
        run: |
          mkdir ../build
          cp -TR . ../build
          tar -cvf deploy.tar ../build/
      - name: Cleaning up existing setup
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          password: ${{ secrets.PASSWORD }}
          # take down docker compose
          script: |
            cd ~/mern-boilerplate
            docker compose -p mern-boilerplate down
            rm -rf ~/mern-boilerplate && mkdir ~/mern-boilerplate
						# feel free to change the name of the folder created
      - name: Adding environment variables
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          password: ${{ secrets.PASSWORD }}
          # create .env file with env keys
          script: |
            cd ~/mern-boilerplate
            touch .env && rm .env
            echo CLIENT_PORT=${{ secrets.CLIENT_PORT }} >> .env
            echo SERVER_PORT=${{ secrets.SERVER_PORT }} >> .env
            echo MONGO_URI=${{ secrets.MONGO_URI }} >> .env
            echo SESSION_SECRET=${{ secrets.SESSION_SECRET }} >> .env
            echo JWT_SECRET=${{ secrets.JWT_SECRET }} >> .env
            echo REFRESH_TOKEN_SECRET=${{ secrets.REFRESH_TOKEN_SECRET }} >> .env
            echo SESSION_EXPIRY=${{ secrets.SESSION_EXPIRY }} >> .env
            echo REFRESH_TOKEN_EXPIRY=${{ secrets.REFRESH_TOKEN_EXPIRY }} >> .env
            echo MAIL_REFRESH_TOKEN=${{ secrets.MAIL_REFRESH_TOKEN }} >> .env
            echo MAIL_CLIENT_ID=${{ secrets.MAIL_CLIENT_ID }} >> .env
            echo MAIL_CLIENT_SECRET=${{ secrets.MAIL_CLIENT_SECRET }} >> .env
						# add additional env keys
      - name: Copy repository to server
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          password: ${{ secrets.PASSWORD }}
          source: 'deploy.tar'
          target: '~/mern-boilerplate/'

      - name: Setup app
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          password: ${{ secrets.PASSWORD }}
          script: |
            cd ~/mern-boilerplate
            tar xf deploy.tar && rm deploy.tar && mv build/* . && rm -rf build/
      - name: Start docker
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          password: ${{ secrets.PASSWORD }}
          command_timeout: 200m
          # cd into respective directory and start docker
          script: |
            cd ~/mern-boilerplate
            docker compose -p mern-boilerplate up -d --build

Adding environment variables

You’ll need to add all of your environment variables as Github SECRETS.

In your repository, go to Settings > Secrets and variables > Actions > New Repository secret

For HOST, USERNAME, PASSWORD, they should be how to SSH into your server. That is, it will try to ssh username@host with the password.

Breakdown of the steps

Tar repository

This step will essentially tar the repository and prepare to upload it to the server.

Cleaning up existing setup

We’re taking down the Docker container and also deleting the folder where the code is. We’re essentially starting from scratch again because we want a new, clean build.

Adding environment variables

We’re going to copy all of the Github Secrets into a .env file. If you have additional environment variables that exist on your server, you can create a .env elsewhere and then cat /shared/projects.env >> .env or something.

Copy repository to server