Development and databases

Deploy Laravel from GitHub with Git and cPanel's .cpanel.yml

Reviewed on 7 min read GitHub deployments

This guide explains the manual cPanel Git and .cpanel.yml workflow for a Laravel application. If you want to manage repositories, scripts, versions and webhooks from the client area, use Deploy+.

The cPanel example updates a working clone. On its own, it does not create isolated releases or guarantee the site stays up without interruption during an update.

Prepare access and the project

Enable SSH and set up a dedicated read-only key for the private repository. Verify GitHub's fingerprint and avoid reusing an identity that has access to other projects.

Work with a test domain and database first. The repository should include the code and composer.lock, but no passwords, production .env or files uploaded by users.

In cPanel > Git Version Control > Create, enter the SSH URL, a private path such as ~/repositories/laravel (replace ~ with your account's directory if the form requires an absolute path) and an identifying name. If you use an SSH alias for the key, use it in the clone URL too.

Check the branch and the content before setting up the deployment.

Define the tasks

Create .cpanel.yml in the repository root. To keep the checks together and stop the process if a command fails, call a versioned script:

---
deployment:
  tasks:
    - /bin/bash /home/usuario_cpanel/repositories/laravel/deploy/cpanel.sh

An example deploy/cpanel.sh would be:

#!/bin/bash
set -euo pipefail
cd /home/usuario_cpanel/repositories/laravel

PHP_BIN=/opt/alt/php83/usr/bin/php
COMPOSER_BIN=/opt/cpanel/composer/bin/composer

test -x "$PHP_BIN"
test -f "$COMPOSER_BIN"
test -f composer.lock
test -f .env

"$PHP_BIN" "$COMPOSER_BIN" install --no-dev --no-interaction --prefer-dist --optimize-autoloader
"$PHP_BIN" artisan config:cache
"$PHP_BIN" artisan view:cache
"$PHP_BIN" artisan route:cache

Replace the user and confirm the PHP and Composer paths in your account. PHP 8.3 is only the example value: the command-line interpreter must be compatible with your application and with the version serving the website. Do not use composer update to resolve dependencies directly in production.

Prepare the private .env, the database and the persistent directories before running the script. If you are migrating an existing application, keep its APP_KEY. Set APP_DEBUG=false. Add whatever asset build the project needs, or publish the assets already built from a compatible environment.

Database migrations need their own tested plan. They are not included here automatically: a code failure does not undo a migration or recover data.

Publish only the public folder

Laravel must be exposed through its public folder, not the repository root. Check the domain's document root and the paths the server allows.

For an addon domain or subdomain, use a path cPanel accepts. If the main domain needs to keep public_html, arrange the right publishing setup with support or with the deployment tool. Do not delete or rename that whole folder without checking other sites, files and services that depend on it.

Before changing how the site is published, keep a copy of the website and the database and agree how to restore the previous destination. Test the project in its staging location first.

Update and deploy

In the cPanel repository, open Manage > Pull or Deploy:

  1. Run Update from Remote to fetch the code.
  2. Check the commit and the branch.
  3. Run Deploy HEAD Commit for the .cpanel.yml tasks.
  4. Follow the log until it finishes and test the website.

Updating from the remote and running the tasks are different operations. If the website serves the clone directly, the first step may already change visible files even if you have not run the second yet.

The equivalent local deployment request is:

/usr/local/cpanel/bin/uapi --output=jsonpretty VersionControlDeployment create \
  repository_root='/home/usuario_cpanel/repositories/laravel'

A result.status of 1 confirms cPanel has accepted the request. Check the task and its log_path until you know the final result; do not read it as "the application is already working".

Automate without overlapping tasks

A push to GitHub does not by itself start the cPanel pull. To automate it you need a receiver or a process that schedules it. Deploy+ offers that integration without you having to build the receiver.

If you maintain your own, validate the provider's signature, the repository and the branch before queuing any work. Use commands and paths defined in your configuration, and hold a lock until the deployment has actually finished. Locking only the call that queues a task does not stop two later tasks from overlapping.

Do not publish a URL that runs commands when visited, and do not pass the webhook content straight into the shell. Log delivery, commit and result without secrets.

Validate and recover

Test the home page, a dynamic route, authentication, forms and assets. Check logs and processes that need to load the new code. If the deployment fails, identify which tasks managed to run before repeating it.

Restoring a previous directory or commit does not roll back databases, .env or shared files. For frequent updates that need to switch between versions, consider Deploy+ or a release strategy with a tested rollback.

You may also find useful

Something wrong or out of date? Tell us and we will review it.