How to Auto-Deploy from GitHub to cPanel with GitHub Actions (2026 Guide)
A complete, copy-paste guide to setting up automatic deployment from GitHub to cPanel shared hosting using GitHub Actions — with working FTP and SSH workflows, secrets setup, and troubleshooting.
If you host on cPanel and still deploy by dragging files into File Manager or pushing over FTP by hand, every release is a chance to upload the wrong file, forget one, or overwrite something in production. This guide fixes that. By the end you'll have a pipeline where every push to your main branch deploys itself to cPanel automatically — no manual uploads, ever.
We'll cover two proven methods (FTP and SSH/rsync), exactly which secrets to set, and how to handle build steps for frameworks like React, Vue, or Laravel. Everything here is copy-paste ready.
Short on time? BabalCloud sets this entire pipeline up for you automatically — it detects your framework, commits the workflow, and configures SSH keys and secrets on its own. See how it works. This guide is for anyone who wants to wire it up by hand.
What "auto-deploy from GitHub to cPanel" actually means
Auto-deployment means a CI/CD pipeline watches your GitHub repository and, whenever you push code, automatically copies the updated files to your cPanel hosting account. On GitHub, the tool that does this is GitHub Actions — free automation that runs in a workflow file inside your repo. You push to main, GitHub Actions runs, and your live site updates in under a minute with zero manual steps.
There are three common ways to connect the two:
- FTP/FTPS deployment — simplest, works on every cPanel plan. GitHub Actions uploads changed files over FTP.
- SSH + rsync — faster and safer for larger sites, but needs SSH access enabled on your host.
- cPanel's native Git Version Control — cPanel pulls from your repo directly using a
.cpanel.ymlfile (no GitHub Actions needed).
We'll set up the first two, since they cover the most cases.
Before you start: what you'll need
- A GitHub repository with your website code.
- A cPanel hosting account (BabalCloud, or any cPanel host).
- Your FTP credentials — host, username, and password (find them in cPanel under FTP Accounts).
- The path to your web root — usually
public_html/for your main domain, orpublic_html/subfolder/for a subdomain.
If your project needs a build step (React, Vue, Next.js static export, Vite, etc.), you'll also need to know your build command (npm run build) and output folder (dist/, build/, or out/).
Method 1: Deploy over FTP (works on every cPanel plan)
FTP is the most reliable method because every cPanel host supports it. We'll use the popular FTP-Deploy-Action, which only uploads files that actually changed — so deploys stay fast.
Step 1 — Store your FTP credentials as GitHub Secrets
Never put passwords in your workflow file. Instead, go to your GitHub repo → Settings → Secrets and variables → Actions → New repository secret, and add three secrets:
| Secret name | Value |
|---|---|
FTP_SERVER | Your FTP host, e.g. ftp.yourdomain.com |
FTP_USERNAME | The FTP account username from cPanel |
FTP_PASSWORD | The FTP account password |
Step 2 — Add the workflow file
In your repository, create a file at .github/workflows/deploy.yml:
name: Deploy to cPanel
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Sync files to cPanel via FTP
uses: SamKirkland/[email protected]
with:
server: ${{ secrets.FTP_SERVER }}
username: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
protocol: ftps
server-dir: ./public_html/
exclude: |
**/.git*
**/.git*/**
**/node_modules/**
.github/**
README.mdThat's the whole thing. Commit and push it to main, then open the Actions tab on GitHub — you'll see the deploy run live. When it finishes, your files are on the server.
A few notes:
protocol: ftpsuses encrypted FTP. Keep it on if your host supports it (BabalCloud does); switch toftponly if you hit connection errors.server-dirmust end in a slash. Use./public_html/for your main domain.- The
excludelist keeps development files off your server. Add anything else you don't want uploaded.
Step 3 — If your project needs a build step
Static apps built with React, Vue, or Vite ship a compiled folder, not raw source. Build it in the pipeline first, then upload only the output:
name: Build and Deploy to cPanel
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Build the site
run: npm run build
- name: Upload build output to cPanel
uses: SamKirkland/[email protected]
with:
server: ${{ secrets.FTP_SERVER }}
username: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
protocol: ftps
local-dir: ./dist/
server-dir: ./public_html/Change local-dir to match your framework's output folder — ./build/ for Create React App, ./out/ for a Next.js static export, ./dist/ for Vite.
Method 2: Deploy with SSH and rsync (faster, cleaner)
If your BabalCloud plan has SSH access enabled, rsync is the better option: it transfers only the byte-level differences between files and can delete files on the server that you removed from your repo, keeping the two perfectly in sync.
Step 1 — Create an SSH key pair
On your computer, generate a key dedicated to deployment:
ssh-keygen -t ed25519 -C "github-deploy" -f deploy_keyThis creates deploy_key (private) and deploy_key.pub (public). Add the public key to cPanel under SSH Access → Manage SSH Keys → Import Key, then click Authorize.
Step 2 — Add SSH secrets to GitHub
Add these repository secrets:
| Secret name | Value |
|---|---|
SSH_HOST | Your server hostname or IP |
SSH_USER | Your cPanel username |
SSH_PRIVATE_KEY | The full contents of the deploy_key file |
Step 3 — Add the rsync workflow
Create .github/workflows/deploy-ssh.yml:
name: Deploy to cPanel via SSH
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Deploy with rsync over SSH
uses: burnett01/[email protected]
with:
switches: -avzr --delete --exclude='.git' --exclude='node_modules'
path: ./
remote_path: /home/${{ secrets.SSH_USER }}/public_html/
remote_host: ${{ secrets.SSH_HOST }}
remote_user: ${{ secrets.SSH_USER }}
remote_key: ${{ secrets.SSH_PRIVATE_KEY }}The --delete flag makes the server match your repo exactly. If that feels risky at first, remove it — files will only ever be added or updated, never deleted.
A note for Laravel and PHP apps
Laravel needs a couple of extra steps because its public folder — not the project root — is what the web should serve. The cleanest pattern on cPanel:
- Deploy your Laravel project to a folder outside
public_html(e.g./home/username/laravelapp/). - Point
public_htmlat the app'spublicfolder, or editindex.phppaths accordingly. - Run
composer install --no-devandphp artisan migrate --forceafter deploy — either over SSH in the workflow, or via cPanel's Terminal.
We cover the full Laravel-on-cPanel setup in a dedicated guide (coming soon). If you're choosing a host for a Laravel project, our hosting plans include the SSH access and PHP version control this workflow needs.
Troubleshooting common problems
The Action fails with "530 Login authentication failed."
Your FTP credentials are wrong or the account is locked. Re-check FTP_USERNAME (it's often the full [email protected] form on cPanel) and reset the password in FTP Accounts if needed.
Files upload but the site shows a blank page or old version.
You likely deployed to the wrong server-dir. Confirm your web root — it's public_html/ for the primary domain and public_html/subdomain/ (or an addon-domain folder) for others.
FTPS connection times out.
Some networks throttle FTPS. Switch protocol: ftps to ftp, or use the SSH method instead, which is more firewall-friendly.
The build step fails with "command not found."
Make sure actions/setup-node runs before your build, and that your package.json has a working build script locally first.
Permission denied over SSH. The public key wasn't authorized in cPanel. Return to Manage SSH Keys and click Authorize next to the imported key.
Frequently asked questions
Is GitHub Actions free for this?
Yes. Public repositories get unlimited GitHub Actions minutes, and private repos include a generous free monthly allowance that's more than enough for typical website deploys.
Do I need a VPS, or does shared hosting work?
Shared cPanel hosting works perfectly for FTP deployment. You only need SSH access for the rsync method — and many cPanel shared plans, including BabalCloud's, offer it.
Will this overwrite my database?
No. This pipeline only deploys files. Your MySQL databases are untouched. For schema changes, run migrations separately (see the Laravel note above).
How do I roll back a bad deploy?
Because everything is in Git, you git revert the bad commit and push — the pipeline redeploys the previous working version automatically. This is the biggest advantage over manual FTP.
Can I deploy only when I choose, instead of on every push?
Yes. Change the trigger to workflow_dispatch to add a manual "Run workflow" button, or deploy only from a release branch or tag.
Wrapping up
Once this is in place, your workflow becomes simply: write code, commit, push. GitHub Actions handles the rest, every version is tracked, and rollbacks take seconds. It's the single biggest quality-of-life upgrade you can add to cPanel hosting.
If you'd rather skip the setup entirely, BabalCloud builds this exact pipeline for you the moment you connect a repository — framework detection, workflow file, SSH keys, and secrets all configured automatically. Either way, you never touch File Manager again.