Deploying a website by dragging files over FTP works until it does not: a half-uploaded change breaks the live site, you cannot tell what changed, and rolling back means digging through a backup. Deploying with Git fixes all of that. This Ultra Web Hosting guide shows you how to push your code to a repository and pull it onto your cPanel account, both through the cPanel Git Version Control interface and straight from the SSH terminal, including a working .cpanel.yml that copies your build into public_html on every deploy.
- Why Deploy with Git Instead of FTP
- Before You Start
- Method A: The cPanel Git Version Control Interface
- Set Up a Read-Only Deploy Key for a Private Repo
- The .cpanel.yml Deployment File
- The Pull-to-Deploy Workflow
- Method B: Deploy Entirely Over SSH
- Deploying a Built App (Node and Next)
- Keep Secrets and node_modules Out of the Repo
- Common Issues
Clone Once, Then Pull to Deploy
Git deployment on cPanel is two moves: clone your repository into the account once, then pull the latest commit whenever you want to go live. cPanel runs a small .cpanel.yml file after each pull to copy files where they belong.
- Push your code to GitHub, GitLab, or Bitbucket as usual
- Clone it into cPanel with Git Version Control, or over SSH
- Add a
.cpanel.ymlthat copies your build intopublic_html - Click Update from Remote then Deploy HEAD Commit to publish
The .cpanel.yml Has to Be in the Repo Root
The single most common reason a Git deploy does nothing: cPanel only runs the deployment steps if a file named .cpanel.yml exists in the top level of the repository. No file, no deploy tasks, and your pulled code just sits in the clone directory instead of appearing on the live site. Section 05 shows a working one.
- Symptom: Deploy HEAD Commit is greyed out or does nothing visible
- Cause: no
.cpanel.ymlin the repo root, or it is malformed YAML - Fix: add a valid
.cpanel.ymlat the repository root and commit it
01. Why Deploy with Git Instead of FTP
FTP moves whole files with no memory of what came before. Git tracks every change as a commit, so your site's history lives in the repository and deploying becomes a single, atomic action rather than a slow trickle of uploaded files. On a shared cPanel account that difference matters more than it sounds.
FTP Uploads
Every deploy is a manual copy with no record of what changed and no clean way back.
- No version history: you cannot see or undo what changed
- Half-uploaded states break the live site mid-transfer
- Easy to overwrite the wrong file or miss one
- Rolling back means restoring from a backup
Git Deploys
Deploys are one command against a full history you can inspect and revert.
- Full version history: every change is a commit you can review
- One-command deploys that either finish or do not apply at all
- Roll back by checking out an earlier commit
- The same repo works on your laptop and the server
Git deployment shines for anything you edit as code: a static site, a PHP app, a WordPress theme or plugin you maintain, or the built output of a Node app. If you only ever tweak content inside the WordPress admin, you do not need Git at all. This guide is for code you version yourself.
02. Before You Start
You need a handful of things in place before the first clone:
- A Git repository for your site, hosted on GitHub, GitLab, Bitbucket, or any Git host you can reach over HTTPS or SSH. This guide assumes your code already lives in one.
- SSH access enabled on your Ultra Web Hosting account. The cPanel Git interface works without it, but private repositories and Method B need SSH. If it is not on yet, see our SSH access guide to request and use it.
- cPanel login for the account, so you can open Git Version Control and the Terminal.
- Your account username and home path. Files live under
/home/youruser/and your live site is usually/home/youruser/public_html. For a map of where things sit, see our server paths guide.
A public repository clones with no credentials, so you can skip straight to Section 03. A private repository needs a deploy key so cPanel can authenticate. If your repo is private, read Section 04 before you try to clone it, or the clone will fail with an authentication error.
03. Method A: The cPanel Git Version Control Interface
cPanel ships a Git Version Control tool that handles cloning and deploying without touching a terminal. This is the friendliest path and the one to start with.
- In cPanel, open Git Version Control (under the Files section).
- Click Create.
- Turn on Clone a Repository.
- In Clone URL, paste your repository's URL. For a private repo over SSH this looks like
[email protected]:youruser/yourrepo.git; for a public repo you can use the HTTPS URL. - Set Repository Path to where the clone should live. Keep it out of the web root, for example
repositories/yoursite, which resolves to/home/youruser/repositories/yoursite. - Give it a Repository Name you will recognize, then click Create.
cPanel clones the repo into that path. It does not put files in public_html yet: that is the job of the .cpanel.yml deployment file in Section 05. The clone directory is your working copy on the server, and the live site is wherever your deploy steps copy the files.
Do not clone directly into public_html. If you do, your entire .git directory and any source files become reachable over the web, which can leak configuration and history. Clone into a directory above the web root (like repositories/) and let .cpanel.yml copy only the files that should be public.
04. Set Up a Read-Only Deploy Key for a Private Repo
To clone a private repository, cPanel authenticates to your Git host with an SSH key. The clean way to do this is a deploy key: an SSH key that grants read-only access to one repository and nothing else. Generate the key on the server, then register its public half with the repo.
Generate the key in cPanel
- In cPanel, open SSH Access, then Manage SSH Keys.
- Click Generate a New Key. Give it a name like
deploy_yoursite, leave the type at ED25519 or RSA 4096, and create it. - Back on the key list, click View/Download next to the public key and copy the full
ssh-ed25519 ...(orssh-rsa ...) line. - You do not need to authorize this key for logging in to your own account. It is only used to read from your Git host.
Add it as a deploy key on your Git host
- GitHub: open the repository, go to Settings > Deploy keys > Add deploy key. Paste the public key, leave Allow write access unchecked, and save.
- GitLab: Settings > Repository > Deploy keys, paste the key, keep it read-only, and add it.
- Bitbucket: Repository settings > Access keys > Add key, paste, save.
Now the clone URL in Section 03 can use the SSH form ([email protected]:youruser/yourrepo.git) and cPanel will authenticate with that deploy key.
A deploy key that can only read means a leak of the server key cannot be used to push malicious commits back into your repository. The server never needs write access to deploy, so do not grant it. One key per repository also lets you revoke a single site's access without touching the others.
05. The .cpanel.yml Deployment File
The .cpanel.yml file is a small YAML script that lives in the root of your repository and tells cPanel what to do after it pulls new code. Without it, deploying does nothing but update the clone. With it, cPanel runs each command under the deployment: tasks: list, which is where you copy your files into public_html.
Here is a working example for a repository whose deployable files sit in the project root. It copies everything into the account's public web directory:
---
deployment:
tasks:
- export DEPLOYPATH=/home/youruser/public_html/
- /bin/cp -R index.html DEPLOYPATH
- /bin/cp -R assets DEPLOYPATH
- /bin/cp -R app DEPLOYPATH
If your site builds into a subfolder such as dist/ or public/, point the copy at that folder instead so only the built output goes live:
---
deployment:
tasks:
- export DEPLOYPATH=/home/youruser/public_html/
- /bin/cp -R dist/. DEPLOYPATH
A few rules that save a lot of confusion:
- The file must be named exactly
.cpanel.yml(note the leading dot) and sit in the repository root, not a subdirectory. - Use two-space indentation and no tabs. YAML rejects tabs, and a stray tab is a common reason the deploy silently fails.
- Reference
DEPLOYPATHafter exporting it, and use full paths for thecpbinary as shown. - Replace
youruserwith your actual cPanel account username.
You commit .cpanel.yml to your repository like any other file, and it travels with your code. That means the deploy recipe is version-controlled alongside the site. Edit it locally, commit, push, and the next pull picks up the new steps. Do not try to create it only on the server: it belongs at the repo root.
06. The Pull-to-Deploy Workflow
With the clone in place and a valid .cpanel.yml committed, your day-to-day loop is short. You work locally, push, and then tell cPanel to fetch and deploy.
- Work locally. Make your changes, commit them, and push to your Git host as usual:
git add -A,git commit -m "your message",git push. - Pull onto the server. In cPanel Git Version Control, click Manage next to the repository, then the Pull or Deploy tab, and click Update from Remote. This fetches your latest commit into the clone.
- Deploy. Click Deploy HEAD Commit. cPanel runs the tasks in
.cpanel.yml, copying your files intopublic_html. The page shows the deploy log and a timestamp when it finishes. - Verify. Load your site in a browser and confirm the change is live.
That is the entire cycle: push, Update from Remote, Deploy HEAD Commit. There is no file dragging and no risk of a half-finished upload, because the deploy either completes or it does not run.
You can skip the manual button clicks by triggering the deploy on a schedule or from a webhook. A cron job that runs git pull in the clone directory keeps a simple site in sync automatically. See our cron jobs guide for how to schedule it.
07. Method B: Deploy Entirely Over SSH
If you would rather live in the terminal, you can do the whole thing over SSH without the cPanel interface. This is often faster once you are comfortable, and it is the only option for scripting deploys.
- Connect. SSH into your account:
ssh [email protected] -p 22. Adjust the port if we gave you a non-standard one. - Clone once. From your home directory, clone the repo into a directory above the web root:
cd ~ git clone [email protected]:youruser/yourrepo.git repositories/yoursite - Deploy the first time. Copy the files into
public_html, either by running the same commands your.cpanel.ymluses or with a direct copy:cd ~/repositories/yoursite /bin/cp -R dist/. ~/public_html/ - Update later. Each time you want to publish new commits, pull and copy again:
cd ~/repositories/yoursite git pull /bin/cp -R dist/. ~/public_html/
You can wrap those last two commands in a one-line shell script in your home directory so a deploy is a single command. Combine that with a cron job and you have a hands-off pull-to-deploy pipeline.
Do not clone the same repository twice, once through the cPanel interface and once by hand, into two different directories. Pick one clone location and use it from both the UI and the terminal. The cPanel Git tool reads the same working copy on disk, so a git pull over SSH shows up in the interface and the other way around.
08. Deploying a Built App (Node and Next)
Static sites and PHP apps deploy the files as they are. A Node app is different: what goes live is the built output, not your source and node_modules. You have two sane options.
Commit the Build
Run npm run build on your machine, commit the built folder, and let .cpanel.yml copy it into public_html. Simple and predictable on shared hosting.
- No build step needed on the server
- What you tested locally is exactly what ships
- Point
.cpanel.ymlat yourdist/orout/folder
Build on Pull
Keep the build out of the repo and run npm ci && npm run build as a task, then copy the result. Cleaner repo, heavier deploy.
- Repository stays free of build artifacts
- Deploy takes longer and uses account resources
- Best when you have a proper build pipeline
For a framework like Next.js exported to static files, build locally, commit the out/ directory, and copy it live:
---
deployment:
tasks:
- export DEPLOYPATH=/home/youruser/public_html/
- /bin/cp -R out/. DEPLOYPATH
Copying built files works for a static export. If your app needs a running Node server (an API, server-side rendering), that is a different setup using the cPanel Node.js application manager rather than a file copy. See Getting Started with NodeJS and Deploying NextJS and React Dashboards for the application-manager path.
09. Keep Secrets and node_modules Out of the Repo
A deployment repo should hold your code and nothing that is either huge or secret. Two files do most of the work here: a good .gitignore, and environment variables for anything sensitive.
A minimal .gitignore for a typical web project:
node_modules/
.env
.env.local
*.log
wp-config.php
/vendor/
- node_modules is rebuilt from
package-lock.jsonwithnpm ci. Committing it bloats the repo and slows every clone. Ignore it. - Secrets go in environment variables or an ignored .env file, never in tracked source. Load them at runtime rather than baking them into committed code.
- Config files with credentials such as
wp-config.phpstay out of the repo. Keep the live copy on the server and ignore it, or template a version without real values.
Database passwords, API keys, and WordPress salts do not belong in a Git repository, especially not one hosted publicly. Once a secret is committed it lives in the history even after you delete it, so it has to be rotated. Add wp-config.php and .env to .gitignore before your first commit, and if a secret ever slips in, change that credential rather than assuming a delete is enough.
10. Common Issues
Deploy HEAD Commit does nothing. There is no .cpanel.yml in the repository root, or its YAML is invalid (usually a tab instead of spaces, or wrong indentation). Add a valid file at the root, commit, push, Update from Remote, then deploy again.
Files land in the wrong place or nothing appears on the site. The DEPLOYPATH in .cpanel.yml is wrong. Confirm your username and that the path is /home/youruser/public_html/ with a trailing slash, and that the cp source matches your actual build folder (dist/., out/., and so on).
Cloning a private repo fails with a permission or authentication error. The deploy key is missing or not attached to the repository. Re-check Section 04: the public key from cPanel must be added as a deploy key on your Git host, and the clone URL must use the SSH form (git@host:user/repo.git), not HTTPS.
Permission denied writing to public_html. The copy is trying to overwrite files owned by another process, or a directory has restrictive permissions. Standard cPanel deploys run as your account user, so make sure nothing under public_html is owned by a different user, and that directories are 755 and files 644.
The pull works over SSH but the cPanel interface looks out of date. They are reading the same clone, so refresh the Git Version Control page. If you truly cloned twice into two directories, delete the extra one and standardize on a single clone path.
The site shows old content after deploy. A caching layer is serving the previous version. Clear your application or CDN cache and hard-refresh the browser. For anything this guide does not cover, open a ticket and we will look at the account with you.
Want a Hand Wiring Up the Deploy?
If the clone, the deploy key, or the .cpanel.yml is fighting you, send us the repository URL and the path you want it deployed to, and we will set up the clone and the deployment steps for you. We support Git deployment on shared, VPS, and dedicated plans.
Quick Recap: Git Deployment in Six Steps
If you only do six things from this guide, do these:
- Enable SSH access on your account so private repos and terminal deploys work.
- Clone the repository outside the web root, into something like
repositories/yoursite, using Git Version Control or the SSH terminal. - Add a read-only deploy key from cPanel to your Git host if the repository is private.
- Commit a valid .cpanel.yml at the repo root that copies your files or build output into
public_html. - Push, then Update from Remote and Deploy HEAD Commit (or
git pulland copy over SSH) to publish. - Keep secrets and node_modules out of the repo with a good
.gitignoreand environment variables.
Last updated July 2026 · Browse all Getting Started articles
