Hosting a React/Vue Application on cPanel with GitHub Actions CI/CD
Tags: webdev, cicd, react, github
Published: 2023-10-03 19:38:34

#Introduction
In this short article, we’ll explore the seamless integration of hosting React or Vue.js applications on cPanel using GitHub Actions for efficient Continuous Integration and Continuous Deployment (CI/CD) in five (5) major steps. 

Learn how to automate the deployment process, ensuring your web applications are always up-to-date and readily accessible to users.

### Step 1 - Domain and Hosting Plan Purchase
Be sure to have purchased your hosting plan and domain name from hosting platforms like Whogohost, Namecheap etc. and login to cPanel.

---


### Step 2 - GitHub workflows setup
In your ready-to-be-deployed React or Vue app, create a `.github/workflows` folder and add `master.yaml` or `main.yaml` depending on the default branch you have on your project repository.

---


### Step 3 - YAML file Config
In the `master.yaml` file created above, paste the following configuration:

```js
name: Deploy to cPanel

on:
  push:
    branches:
      - master

jobs:
  deploy:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [14.x, 16.x, 18.x]

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

      - name: Install Dependencies 📦
        run: npm install

      - name: Build React App / Vue App (depending on user app) 🏗️
        run: npm run build

      - name: Upload to cPanel 📂
        uses: SamKirkland/FTP-Deploy-Action@v4.3.4
        with:
          server: ${{ secrets.FTP_SERVER }}
          username: ${{ secrets.FTP_USERNAME }}
          password: ${{ secrets.FTP_PASSWORD }}
          server-dir: /public_html/
          exclude: |
            **/.git**
            **/.git*/**
            **/node_modules/**
            **/.**
```
Here is a Breakdown of the config above:

1. **File Header:**
   - `name: Deploy to cPanel`: This is just a title for the workflow. It's a description of what this automated process does.

2. **Event Trigger:**
   - `on:`: This section defines when this workflow should run.
   - `push:`: It runs when there is a push event (a code change) in the repository.
   - `branches:`: Specifies which branch should trigger this workflow. In this case, it's set to only run when changes are pushed to the `master` branch.

3. **Job Configuration:**
   - `jobs:`: This section defines the jobs to be executed as part of the workflow.
   - `deploy:`: It's the name of the job, you can think of it as a task within the workflow.
   - `runs-on: ubuntu-latest`: This job will run on a virtual machine running the latest version of Ubuntu.

4. **Matrix Strategy:**
   - `strategy:`: Here, you configure a strategy for running the job in different environments.
   - `matrix:`: This allows you to run the job with different versions of Node.js. In this case, it's configured to run with Node.js versions 14.x, 16.x, and 18.x.

5. **Step in the Job:**
   - `steps:`: This section lists the individual steps that should be executed within the job.

6. **Checkout Code 🚚:**
   - `name: Checkout Code 🚚`: This is just a label for the step, describing what it does.
   - `uses: actions/checkout@v3`: This step uses a pre-built GitHub Action called `actions/checkout@v3` to fetch the latest code from the repository.

7. **Install Dependencies 📦:**
   - `name: Install Dependencies 📦`: Another labeled step.
   - `run: npm install`: It runs the command to install Node.js dependencies.

8. **Build React App 🏗️:**
   - `name: Build React App 🏗️`: Another labeled step.
   - `run: npm run build`: This step builds a React web application.

9. **Upload to cPanel 📂:**
   - `name: Upload to cPanel 📂`: Labeled step.

- `uses: SamKirkland/FTP-Deploy-Action@v4.3.4`: This step uses a GitHub Action called `SamKirkland/FTP-Deploy-Action` to deploy the code.

   - `with:`: Here, it specifies configuration options for the deployment, including the FTP server details, server directory, and files to exclude during the upload.

    - `server`: secrets.FTP_SERVER: This is using a secret named FTP_SERVER. It's likely storing the FTP server address or hostname (eg:https://emmanuel.com). This way, you're not exposing the actual server address in your workflow file, which is a security best practice.

    - `username`: secrets.FTP_USERNAME: This uses another secret named FTP_USERNAME to store the FTP username or login (your cPanel username in this case).

   - `password`: secrets.FTP_PASSWORD: Similarly, this uses a secret named FTP_PASSWORD to store the FTP password (your cPanel password in this case). By using secrets, you ensure that sensitive information is not exposed in the workflow file, keeping your credentials secure.


> Head over to your project repository and set up the FTP server name, username, and password by clicking on **setting**. Under the security list click on **Secrets and variables** >> **New repository secrets** to add.


![GitHub Actions Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r2ax39o08ixucj00zmub.png)


In summary, this YAML file sets up an automated workflow that triggers when changes are pushed to the `master` branch of a GitHub repository. It checks out the code, installs dependencies, builds a React app, and then deploys it to a cPanel server via FTP using a specific GitHub Action. This workflow is designed to automate the process of deploying a web application to a cPanel hosting environment.

---


### Step 4 - Deploymemt and cPanel file manager setup
* After the `yaml` file is set, Next is to build your project locally and then push to Github. Header over to `Actions` option on GitHub and observe your the build stages to ensure all jobs were completed successfully.


 
![GitHub Deployment Done](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/83i9sgl6osx44kgc0srw.png)
 
*  Next, head over to your logged-in cPanel, click on file manager to expose the folder, and observe if your work folders are complete and in order.
*  Next, copy the index.html in your `dist `folder to the `public_html` folder and refresh your domain name on the web browser
1.   ![cPanel Dashbaord](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1m7ssm2pap2nq1uedc9h.png)
2.   ![cPanel file manager](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/on5ebgxyzv9ee53uowtv.png)


* Congratulation! Your website is live at this stage.

---


### Step 5 - Debugging and .htaccess file config
If your website is only a single page without external links or routes then you are good to go, if not you might observe that when you click on a route and try to refresh the page, a 404 screen pops up like below:

![404 error screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vo2yt4nr1q3a1eh7t9fg.png)

This is where the `.htcaccess` file comes in.

#### What is an .htaccess file?
An `.htaccess` file, short for "hypertext access," is a configuration file used on web servers, particularly Apache servers. It allows you to configure various server settings and behaviors for specific directories or the entire website. `.htaccess` files are commonly used for tasks like URL rewriting, access control, and setting custom error pages.

Now that we know what an `.htaccess` file is, there in the file manager, we click on show hidden files and on the top left add a new file. This time we create an `.htaccess` file and paste in the following:

```bash
/* <IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteBase /
 RewriteRule ^index\.html$ - [L]
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteRule . /index.html [L]
 </IfModule> */
```
Here is a breakdown of the file:

**<IfModule mod_rewrite.c>**: This is the start of an <IfModule> block. It's used to conditionally execute the contained directives only if the mod_rewrite module is available and enabled on the server. mod_rewrite is a powerful Apache module used for URL rewriting and redirection.

**RewriteEngine On**: This directive enables the mod_rewrite engine, allowing the server to process URL rewriting rules.

**RewriteBase /**: This sets the base URL path for relative substitution in the subsequent RewriteRule directives. In this case, it's set to the root directory of the website.

**RewriteRule ^index\.html$ - [L]**: This RewriteRule is used to rewrite URLs. It's configured to match requests for index.html exactly and doesn't perform any actual rewriting. The - (dash) means no substitution, and [L] specifies that this is the last rule to be processed if matched.

**RewriteCond %{REQUEST_FILENAME} !-f**: This RewriteCond directive is a condition that checks if the requested filename does not exist as a regular file (!-f condition).

**RewriteCond %{REQUEST_FILENAME} !-d:** This RewriteCond directive is another condition that checks if the requested filename does not exist as a directory (!-d condition).

**RewriteRule . /index.html [L]**: If the conditions in the previous two lines are met (the requested file doesn't exist as a regular file or directory), this RewriteRule is applied. It rewrites the request to index.html, effectively directing all requests to the index.html file. [L] specifies that this is the last rule to be processed if matched.

**</IfModule>**: This is the closing tag for the <IfModule> block, indicating the end of the conditional section.

In summary, this `.htaccess` file is often used in the context of single-page applications (SPAs) or front-end frameworks where the server is configured to route all requests to a single HTML file (in this case, index.html). If a requested file doesn't exist or is not a directory, it redirects the request to the index.html file, effectively allowing client-side routing to handle the request. However, please note that the use of /* as comment delimiters is unconventional in `.htaccess` files, and it's generally recommended to use # for comments.
    
    
So there we have it, the deployed website is configured and functioning properly while the GitHub Action CI/CD is ready to take on subsequent deployments automatically.