CI/CD with Github Actions – How to Deploy a Next.js Application with CI/CD

Share:

TABLE OF CONTENTS

1. Introduction

This guide covers the process of deploying a Next.js application with a CI/CD pipeline, using Docker for containerization and GitHub Actions for automation. We’ll also configure NGINX as a reverse proxy, secure the app with SSL certificates, and deploy it using a custom domain.

Brief overview of the tools involved:

  • Next.js: React-based framework for building web applications.
  • Docker: Containerization tool for creating consistent environments.
  • GitHub Actions: CI/CD automation tool.
  • GitHub Packages: Package hosting service for Docker images.
  • NGINX: Web server to serve the Next.js app as a reverse proxy.
  • SSL: Securing the app using SSL certificates.
  • Domain: Setting up a custom domain for the application.

2. Prerequisites

Before proceeding with the deployment, ensure you have the following:

  • Knowledge of Docker: Basic understanding of Docker is required.
  • GitHub repository: The Next.js application should be hosted in a GitHub repository.
  • GitHub Packages: For storing and managing Docker images.
  • Access to a server: A VPS or similar server where you will host your application.
  • NGINX: Installed and configured as a reverse proxy on your server.
  • Domain name: You should have already purchased a custom domain.
  • SSL certificate: Obtain an SSL certificate (e.g., using Let’s Encrypt or a similar service).

3. Dockerize the Next.js Application

To ensure that your Next.js application can run consistently across different environments, you need to containerize it using Docker. This involves creating a Dockerfile, which defines the environment and instructions for building and running your application in a container.

Here I’m using business-model-canvas application as example.

3.1 Create a Dockerfile:
In the root of your Next.js project, create a Dockerfile that defines how to build and run your application.

FROM softeko/bmc-generator-base AS builder

WORKDIR /app

COPY package*.json ./

RUN npm install -g [email protected] && \
    npm install --omit-dev

COPY . .

RUN npm run build

RUN npx playwright install chromium

FROM softeko/bmc-generator-base

WORKDIR /app

COPY --from=builder /app .
COPY --from=builder /root/.cache/ms-playwright /root/.cache/ms-playwright

EXPOSE 5000

CMD ["npm", "start"]

3.2 Create a .dockerignore file:
In the root of your project, create a .dockerignore file to exclude unnecessary files from the Docker build context (e.g., node_modules, logs, etc.). This helps reduce the image size and build time.

.git
.next
.husky
.vscode
.gitignore
.dockerignore

public
README.md
Dockerfile
node_modules
npm-debug.log

3.3 Build the Docker image locally:
Once the Dockerfile is ready, build the Docker image by running the following command in your terminal:

 docker image build -t bmc-generator:1.0 .

3.4 Run the Docker container:
After building the image, run the container to verify the application works as expected:

docker container run -d --name bmc-generator -p 5000:5000 bmc-generator:1.0

3.5 Verify the application:
Open a browser and navigate to http://localhost:5000 to check if your Next.js application is running inside the Docker container. If everything is ok then you can now proceed to set up CI/CD to automate the building and deployment process.

Optional:
Now you can make commit after adding Dockerfile and .dockerignore files. Example commit message Add Dockerfile and .dockerignore files.

4. Add repository secrets & variables

Go the bmc-generator > Settings > Secrets and variables > Actions > Variables > New repository variable and the following variables:

  • ENV
  • GHCR_PAT
  • VPS_HOST
  • VPS_PASSWORD
  • VPS_USER

5. Setting up CI/CD with GitHub Actions

To automate the build and deployment process, we will use GitHub Actions to build a Docker image from the Next.js application and deploy it to a VPS server. The process will be triggered on each push to the main branch.

5.1 GitHub Actions Workflow:

Create a .github/workflows/deploy.yml file in your repository with the following content:

name: Build and Deploy Docker Image

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-22.04

    steps:
      - name: Checkout Code from Repository
        uses: actions/checkout@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
        with:
          install: true

      - name: Create .env file
        run: |
          echo "${{ vars.ENV }}" > .env

      - name: Log in to GitHub Container Registry
        run: echo "${{ vars.GHCR_PAT }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin

      - name: Build and push Docker image
        uses: docker/build-push-action@v3
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ghcr.io/bmc-business-model-canvas/bmc-generator:latest

  deploy:
    runs-on: ubuntu-22.04
    needs: build

    steps:
      - name: Checkout Code from Repository
        uses: actions/checkout@v3

      - name: Install sshpass
        run: sudo apt-get install -y sshpass

      - name: Deploy Docker Container to VPS
        env:
          SSH_PASSWORD: ${{ vars.VPS_PASSWORD }}
        run: |
          sshpass -p $SSH_PASSWORD ssh -o StrictHostKeyChecking=no ${{ vars.VPS_USER }}@${{ vars.VPS_HOST }} << 'EOF'
              docker login ghcr.io -u ${{ github.actor }} --password ${{ vars.GHCR_PAT }}

              if [ "$(docker ps -q -f name=bmc-generator)" ]; then
                  docker container stop bmc-generator
              fi

              if [ "$(docker container ls -a -q -f name=bmc-generator)" ]; then
                  docker container rm bmc-generator
              fi

              docker image pull ghcr.io/bmc-business-model-canvas/bmc-generator
              docker run -d --name bmc-generator -p 5000:5000 ghcr.io/bmc-business-model-canvas/bmc-generator
              docker image prune -f
          EOF

5.2 Workflow Explanation:

5.2.1 Build Job:

  • Checkout Code: Fetch the repository’s code.
  • Set up Docker Buildx: Prepares the environment for building and pushing Docker images.
  • Create .env file: Creates a .env file using environment variables.
  • Log in to GitHub Container Registry: Authenticates to GitHub Packages.
  • Build and Push Docker Image: Builds the Docker image using the Dockerfile and pushes it to the GitHub Container Registry.

5.2.2 Deploy Job:

  • Install sshpass: Installs sshpass to facilitate SSH connections to the VPS.
  • Deploy Docker Container to VPS: SSH into the VPS, stop any existing containers, remove them, pull the latest image, run the new container, and clean up unused images.

With this workflow in place, the Docker image will be built and deployed to your VPS whenever there is a push to the main branch.

6. Configure NGINX as a Reverse Proxy

Once your Docker container is running on the VPS, you need to configure NGINX as a reverse proxy to route traffic to your application on port 5000. Additionally, we’ll create a symbolic link to enable this configuration.

6.1 (Optional) Install NGINX:
If you don’t already have NGINX installed on your VPS, install it with the following commands:

sudo apt-get update
sudo apt-get install nginx

6.2 Create NGINX Configuration:
Create a new configuration file for your application. Use the nano editor to create the file:

sudo nano /etc/nginx/sites-available/bmc.softekocms.com

Add the following configuration according to you application:

server {
    listen 80;
    server_name bmc.softekocms.com www.bmc.softekocms.com;

    location / {
        proxy_pass http://localhost:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

6.3 Create a Symbolic Link:
To enable this configuration, create a symbolic link from sites-available to sites-enabled:

sudo ln -s /etc/nginx/sites-available/bmc.softekocms.com /etc/nginx/sites-enabled/

6.4 Test NGINX Configuration:
Test if the NGINX configuration is valid by running:

sudo nginx -t

6.5 Reload NGINX:
After confirming the configuration is valid, reload NGINX to apply the changes:

sudo systemctl reload nginx

Now NGINX will forward requests from bmc.softekocms.com to your Docker container running the Next.js application on port 5000.

7. Setting Up SSL with Certbot

To secure your application with SSL, you can use Certbot to generate and manage SSL certificates from Let’s Encrypt. This section will guide you through setting up SSL using Python Certbot.

7.1 (Optional) Install Certbot:
If you don’t have Certbot installed, you can install the Python Certbot package with the following commands:

sudo apt-get update
sudo apt-get install certbot python3-certbot-nginx

7.2 Obtain an SSL Certificate:
Run the following command to obtain an SSL certificate for your domain bmc.softekocms.com:

sudo certbot --nginx -d bmc.softekocms.com -d www.bmc.softekocms.com

Note: When running Certbot for the first time, you may be prompted to provide an email address for urgent renewal and security notices.

Certbot will automatically configure NGINX to use the SSL certificate. Follow the on-screen prompts to complete the process.

7.3 Reload NGINX:
After confirming the configuration is valid, reload NGINX to apply the changes:

sudo systemctl reload nginx

Your application is now secured with an SSL certificate, and all traffic to bmc.softekocms.com will be encrypted.

  • Welcome to our blog details page, your gateway to in-depth captivating narratives. Dive into thought-provoking articles,and engaging content that goes beyond the surface

    View all posts

Send Us A Message

Connect with Softeko

Please fill out the form and a representative from our team will be in touch with you shortly. We strive to respond to all inquiries within 24 hours during business days. Also, you can reach us directly via social media. We are available on Facebook, YouTube, & LinkedIn.

Your Success Starts Here!

Please enable JavaScript in your browser to complete this form.
Name