Deploy your project to cPanel

Sanil Manandhar
9 min readAug 4, 2023

--

While researching the proper method for deploying a Laravel project to cPanel, I found that many of the online resources had a way of deploying the project in a way that I found to not be the best.

Most of them followed one of the following two methods:

  • Putting the entire project inside the public_html folder which exposes all of the files including the .env files and other important files to the general public and increases the security risk
  • Uploading the project folders inside the cPanel and copying the public folder to public_html and modifying the public/index.php file

Upon further research, I found another way (that I felt was better) for properly deploying the project to cPanel and I wanted to write about the process I followed so that others may have access to the information as well. Similar steps can also be followed for projects that are not in Laravel but are in a different language/framework.

The steps that I will be mentioning assume that your cPanel has access to the terminal and has the necessary tools like composer installed and that you have a GitHub account (or other versioning tools).

I will be explaining how I configured the project on cPanel, wrote a deployment script that can be run manually(can be made to deploy on push) from GitHub, and how I used a different php version than the default version specified by the cPanel for the repository.

Configuration of the application on cPanel

Step 1: Configure Git on cPanel

We will be configuring the public and private keys in this step so that, we can access our GitHub easily.

  • Login to your cPanel account
  • Open your terminal and run the command
ssh-keygen -t rsa -b 4096 -C "USERNAME"

The above command will generate a pair of public and private keys which will be saved as id_rsa.pub and id_rsa respectively. You can access the keys by moving into the folder .ssh.

  • Open and copy the content of the public key (id_rsa.pub) to use on GitHub
cat ~/.ssh/id_rsa.pub

This key generation process can also be done by going directly to the ‘SSH ACCESS’ menu present in the ‘Security’ section of the cPanel tools.

After generating the key, we need to copy the contents of the public key to GitHub. Access the key content as shown above, copy the content, and go to GitHub.

Go to your project's repository and inside ‘Deploy Keys’ under ‘Security’ of your repository’s ‘Settings’, click on the ‘Add Deploy Key’ button.

Here you can give a title for the key and paste the content of the key in the ‘Key’ section and then click on the ‘Add Key’ button.

Step 2: Setup application for using git

In this step, we will perform the required steps for using git from the cPanel terminal.

  • Go to the terminal of the cPanel
  • Set the name and email to be used for your repository
git config user.name "Your Name"
git config user.email "your@email.com"
  • Clone the repository from GitHub
git clone git@github.com:username/repo.git

The clone URL can be obtained from GitHub by going to the repository, clicking on the ‘Code’, and copying the content present on the ‘SSH’ tab.

The above command will clone the repository content by creating a folder name the same as the repository name. If you want a different folder name use the command given below where ‘folderName’ will be the name of the folder where your contents will be placed.

git clone git@github.com:username/repo.git folderName

After cloning the project, you can run the composer and artisan commands that you need to run such as ‘composer install’, ‘php artisan key:generate’, and so on. Also, you need to create a copy of the ‘.env.example’ file and rename it to ‘.env’ and modify the contents as needed.

Step 3: Creating a Symbolic Link of the project’s public folder to public_html

In this step, we will be creating a symlink of the project’s public folder to the public_html so that the project’s public folder will be accessible to the general public.

  • Create a backup of the public_html folder (in case something goes wrong) and delete it
  • Create the symlink
ln -s /home/user/folderName/public /home/user/public_html

Here, ‘/home/user/folderName/public’ is the location of the project’s public folder (the one we cloned previously). If you do not know the location, you can just open the terminal, go into the project’s directory using ‘cd folderName’ and then once you are inside the desired location, use ‘pwd’ to get the location.

‘/home/user/public_html’ is the location of the public_html folder. You can use a similar method (mentioned above) to get the actual location.

If you need to use the symlink for your storage files as well use the commands

ln -s /home/user/folderName/storage/app/public /home/user/public_html/storage
php artisan storage:link

With this, we are done. Your project should now run and if you make any changes to the repository on GitHub, you can simply go to the terminal of cPanel, go to the project directory and run ‘git pull’. You can also do other things such as creating new branches, checking out branches, and so on.

Creating a deployment script on GitHub

For the deployment script, we will be writing a ‘yml’ file that will be responsible for performing certain actions in the cPanel application when we direct GitHub to do so (manually).

Step 1: Creating a deployment script

  • Go to your GitHub account and click on the ‘Actions’ tab
  • There are many options that GitHub provides for your repository but for now, click on the ‘set up a workflow yourself’
  • This will create a new yml file inside your repository which will be responsible for deploying the application to cPanel
name: Deploy to production
on:
workflow_dispatch:
inputs:
branch_to_deploy:
description: 'Branch to deploy'
required: true

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Check out the code
uses: actions/checkout@v2

- name: Run deploy script
uses: appleboy/ssh-action@master
with:
username: ${{ secrets.SSH_USERNAME }}
host: ${{ secrets.SSH_HOST }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: 'cd /home/user/folderName && ./deploy_script.sh ${{ github.event.inputs.branch_to_deploy }}'

The above is the yml file that I wrote for my application. You can modify it according to your needs.

Writing a brief explanation of the yml file, ‘on :workflow_dispatch’ means that the code will be run when the user (me) decides to run the deployment manually. The ‘inputs’ section specifies that the user will have to input the name of the branch to deploy which will be stored as a variable.

The ‘actions/checkout@v2' is used to checkout the code from the repository into the virtual machine. ‘appleboy/ssh-action@master’ is used so that we can ssh into the cPanel terminal and run the required script there. For performing the ssh action, we will need to define some secret variables (defined under with:) which we will be creating on GitHub in the next step. I have used the ‘key: ${{ secrets.SSH_PRIVATE_KEY }}’ as I will be using the public/private key (created above) for the ssh process, if you want to use the password instead, you will need to update the script accordingly.

The script section will contain the actual commands that you want to run after successfully performing the ssh action. In my case, I have written the commands on a bash file named ‘deploy_script.sh’ and have passed the variable ‘branch_to_deploy’ to the file. You can also write the commands in the yml file instead of creating a separate bash file.

The bash file I created looked something like this:

#!/bin/bash

# Get the branch name provided as an argument to the script
BRANCH_TO_DEPLOY=$1

if git ls-remote --exit-code --heads origin "$BRANCH_TO_DEPLOY" > /dev/null; then
# Go to the master branch
git checkout master

if [ "$BRANCH_TO_DEPLOY" = "master" ]; then
# Pull the latest changes
git pull
echo "Deployment of $BRANCH_TO_DEPLOY is complete."
exit
fi

# Check if the branch_to_deploy exists
if git rev-parse --quiet --verify "$BRANCH_TO_DEPLOY" > /dev/null; then
# Delete the branch_to_deploy if it exists
git branch -D "$BRANCH_TO_DEPLOY"
fi

git pull

# Create and switch to the branch_to_deploy
git checkout "$BRANCH_TO_DEPLOY"

echo "Deployment of $BRANCH_TO_DEPLOY is complete."
else
echo "Branch $BRANCH_TO_DEPLOY does not exist remotely."
fi

It’s a simple script that just takes the value of the branch_to_deploy variable, checks if the branch exists or not, pulls the latest changes and checks out to the branch. You can also perform other operations such as ‘composer install’ or run commands using ‘php artisan …’ and so on. In my case, I did not need to perform the complex actions so just wrote a small and simple script.

Step 2: Creating the secret variables on GitHub

  • Make sure that the public key generated above i.e. id_rsa.pub is authorized. You can do this by going to the terminal of cPanel, heading into the .ssh folder, and appending the content of the generated ‘id_rsa.pub’ key to the authorized_keys file. Or, you can also do this from the UI of ‘SSH Access’ present as a tool on cPanel
  • Copy the contents of the ‘id_rsa’ (private key) to use for the deployment on GitHub
  • We will also need the values of the ‘current user’ and the ‘shared IP address’ which can be easily seen on the right side when you login into the cPanel
  • Go to Github -> your repository -> Settings -> Secrets and variables -> Actions. Here, click on the ‘New repository secret’ button and add the name and the values as required. From the above script, ‘SSH_HOST’ will contain the ‘shared IP address’, ‘SSH_PRIVATE_KEY’ will contain the private key, and ‘SSH_USERNAME’ will contain the ‘current user’

Once this is done, you are ready to deploy your script. Merge the branch to the master branch and head on over to the ‘Actions’ tab.

On the left side, you can see your scripts. Select the script labeled ‘Deploy to production’ and on the right side you will see a button labeled ‘Run workflow’. There you should be able to input the name of the branch you wish to deploy and then click on ‘Run workflow’ which will deploy the branch.

You can also modify the yml script to run the deploy process as soon as someone pushes to the master branch or when some other condition is satisfied as well. In such a case, you will not have to go to the action tab to deploy the branch manually. In my case, I made the script as above since I needed to deploy different branches to production at a desired time, not just the master branch.

Running terminal commands using a different PHP version for a project in cPanel

The project I deployed needed to use php version 7.4 but the cPanel was using php version 7.2 globally which was causing issues when I tried to run any composer commands within the directory where I cloned my project.

cPanel has the ‘MultiPHP Manager’ feature which allows you to use different php versions but it seems to work only with folders that are inside the public_html folder. Since I had kept my project folder outside the public_html folder, using the said feature did not work for me.

Upon researching how I could use a different php version for a particular directory, most sources told me to use a .htaccess file that would direct cPanel to use the specified php version inside the folder. (This did not work for me but I am going to write it here so that you can try it and maybe it would work for you).

For using php version 7.4 inside the folderName directory, create a ‘.htaccess’ file inside the directory and copy the contents:

<IfModule mime_module>
AddHandler application/x-httpd-ea-php74 .php .php7 .phtml
</IfModule>

As this did not work for me, I had to search for an alternative. After searching long and hard I finally found a working alternative.

Instead of running the php commands as ‘php artisan …’ which will use the php version 7.2, we could just specify the version of the php for running the command as:

/opt/cpanel/ea-php74/root/usr/bin/php artisan ...

‘/opt/cpanel/ea-php74/root/usr/bin/’ is the location of the php version 7.4 on my cPanel and it may be different for you. This worked really well for me and I did not find sources specifying this method so I decided to include this here.

That’s all for now. Happy Coding everybody.

--

--