Simplified CI/CD | Automating Next.js Deployment with GitHub Actions on cPanel Hosting

Roshan Paudel
21 Dec 2024

Optimizing CI/CD Pipelines in GitHub Actions - ActiveState

Today, I am going to talk about how to publish your site on cPanel hosting using a CI/CD model leveraging GitHub Actions.

Next.js offers a very fluent and easy development experience when you use Vercel. It provides automatic deployment, building, testing, and various other features. However, when you detach a Next.js app from Vercel's deployment, things can quickly become challenging.

My main issue with Vercel was its caching system and unpredictable behavior during deployments. When I used server functions and API routes, even when explicitly disabling caching, Vercel would still cache data. While everything would work fine locally, it would behave differently on Vercel.

So, I decided to explore other alternatives and found that cheaper hosting providers offer cPanel hosting where I could host Node.js applications. However, moving away from Vercel meant compromising on several features. Despite this, using Next.js still provided significant benefits that I was not willing to trade off.

One day, I decided to move my project away from Vercel and set up a Node.js app on cPanel with a custom server.

For those who are not familiar with creating a custom server, I would recommend reading this article: Building Your Application: Custom Server.

However, many problems arose during this transition. Previously, I had CI/CD pipelines with Vercel, which meant I didn't need to worry about building the application and manually moving it to the server by zipping the build and extracting it there, followed by navigating through cPanel to restart the server.

Thus, today I delved a little deeper into GitHub Actions and aimed to automate what I used to do manually.

My manual deployment process looked like this:

  1. Step 1: Make changes to the code and push them to GitHub.
  2. Step 2: SSH into the server to pull these changes.
  3. Step 3: Return to the local machine to build the application. Since the server's memory and CPU were too low, building it there wasn't feasible.
  4. Step 4: Sync the changes using the rsync command from the local machine. Essentially, this command copies all modifications from my machine to the server.
  5. Step 5: Navigate to my application in cPanel and restart it by clicking the restart button.

Now that I've learned about GitHub Actions, I wanted to automate all these steps using GitHub Actions. It was a fairly simple process. I had to utilize different tools that people had already developed and create a yaml file in the .github/workflows/ directory of my project folder.

Firstly, we need to create a workflow file. To do this, you can navigate to the "Actions" tab on GitHub, then go to the "Automation" section. Choose "Manual" and commit that file with an example. You can modify this file later as needed.

The next step is to write the YAML file:

      - main
name: 🚀 Deploy app on push

# Here we can define env(s) for our application building. These comes form variables that
# we put on a repository. To put variables you have to go to a repo and from there : 
# Settings>Secrets&variables>Actions>Variables and add variables that you require. Those 
# variables can be accessed using ${{vars.VARIABLE_NAME}} 

  MONGO_URI: ${{vars.MONGO_URI}}

    name: 🎉 Deploy
    runs-on: ubuntu-latest
    - name: 🚚 Get latest code
      uses: actions/checkout@v3

    - name: 🖥 Use Node.js 21uses: actions/setup-node@v2
        node-version: '21'
    - name: 🔨 Build Projectrun: |
        npm install
        npm run build 

    - name: 📂 Copy Build Files to the server
      uses: appleboy/scp-action@v0.1.7with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        password: ${{ secrets.PASSWORD }}
        port: ${{ secrets.PORT }}
        source: ".next"target: ~/banshwali-admin/

    - name: ♻️ Restart the server
      uses: appleboy/ssh-action@master
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        password: ${{ secrets.PASSWORD }}
        script: |
           cd ~/MY_PROJECT &&
           git pull &&
           touch ~/MY_PROJECT/tmp/restart.txt

You can find your YAML file in .github/workflows/manual.yml in your project's root directory if you've created it from GitHub Actions. Otherwise, you can also create a folder like that and add the YAML file.

The next step is to add necessary secrets in the GitHub repo. To add the keys, you can navigate to the "Settings" tab and then select "Secrets and Variables." Choose "Actions," and add the host, username, and password that we've used in the YAML file. The hostname refers to the IP address of your server. All the credentials are provided by the service providers.

Now that we've set up our project, let's discuss what I'm doing in the YAML file. I'll briefly explain each step:

  1. Get latest code: This step checks out the latest code from the repository.
  2. Use Node.js 21: Sets up the Node.js environment with version 21.
  3. Build Project: Installs dependencies and builds the project.
  4. Copy Build Files to the server: Uses SCP (Secure Copy Protocol) to copy the built files to the server.
  5. Restart the server: Uses SSH to connect to the server, pull the latest changes from the repository, and restart the server.

cPanel uses Phusion Passenger to handle the deployment of NodeJS and Ruby applications. If you make a change to your application Passenger is not immediately restarted.

By automating these steps with GitHub Actions, we can streamline the deployment process and ensure consistency in our deployments.

Share this article in social media

© 2024 Roshan Paudel