
Developers using shared hosting often find themselves manually uploading files via FTP every time they make code changes — time-consuming and error-prone. The good news is that hosting with SSH support can be configured to deploy automatically on every git push using a Git bare repository and a post-receive hook. This guide walks through the full setup on DirectAdmin hosting.
Prerequisites: Hosting with SSH access enabled, Git installed locally (check with git --version), a GitHub or GitLab repository.
1. What Is CI/CD on Hosting?
CI/CD (Continuous Integration / Continuous Deployment) automates the process of getting code changes onto a live server. For shared hosting, the practical approach is a Git bare repository on the server combined with a post-receive hook — a shell script that runs automatically whenever code is pushed.
The flow is: push code from your local machine to the hosting server → the post-receive hook runs git checkout automatically → updated files appear in public_html instantly.
2. What You Need
- Hosting with SSH access enabled (request via DirectAdmin or a Support Ticket)
- Git installed on your local machine
- An SSH key for authentication (recommended over password)
- A GitHub or GitLab repository (if you want webhook-triggered deploys)
AsiaGB Hosting: SSH access can be enabled by submitting a Support Ticket with your hosting username. Our team will activate it within 24 hours.
3. Create a Git Bare Repository on the Server
Connect via SSH and create a bare repository outside public_html:
# Connect via SSH ssh [email protected] # Create a folder for the bare repo (outside public_html) mkdir ~/repos cd ~/repos git init --bare mysite.git
A bare repository has no working directory — it acts purely as a receiving endpoint for pushes, not as a place to store editable files.
4. Create the post-receive Hook Script
A hook script is a shell script Git runs automatically after receiving a push. Create the hook file:
nano ~/repos/mysite.git/hooks/post-receive
Paste the content below, replacing /home/username/public_html with your actual path:
#!/bin/bash
# post-receive hook — deploy to public_html
GIT_WORK_TREE=/home/username/public_html
export GIT_WORK_TREE
GIT_DIR=/home/username/repos/mysite.git
export GIT_DIR
git checkout -f main
echo "Deploy complete: $(date)"Save the file, then make it executable:
chmod +x ~/repos/mysite.git/hooks/post-receive
⚠️ Check your branch name: If your repository uses master instead of main, change git checkout -f main to git checkout -f master.
5. Add the Remote on Your Local Machine
In your local project directory, add the hosting server as a Git remote:
# Navigate to your local project cd ~/myproject # Add the hosting server as a remote named "hosting" git remote add hosting ssh://[email protected]/home/username/repos/mysite.git # Test with your first push git push hosting main
If everything is configured correctly, you'll see the "Deploy complete" message from the hook, and your updated files will appear in public_html immediately.
6. GitHub/GitLab Webhook (Advanced)
To trigger a deploy automatically whenever you push to GitHub or GitLab, create a PHP webhook receiver in public_html:
# Create deploy.php in public_html
<?php
$secret = 'YOUR_WEBHOOK_SECRET';
$payload = file_get_contents('php://input');
$sig = 'sha256=' . hash_hmac('sha256', $payload, $secret);
if (!hash_equals($sig, $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '')) {
http_response_code(403); exit;
}
exec('cd /home/username/repos/mysite.git && git fetch && GIT_WORK_TREE=/home/username/public_html git checkout -f main 2>&1', $out);
echo implode("\n", $out);Then add a webhook in GitHub under Settings → Webhooks, set the Payload URL to https://yourdomain.com/deploy.php, and enter the same secret string.
7. Test the Automatic Deployment
Make any change locally and push:
git add . git commit -m "test: auto deploy" git push hosting main
Open your website — the change should appear immediately after a successful push.
8. Hosting vs VPS Limitations
| Capability | Shared Hosting | VPS |
|---|---|---|
| Git bare repository | ✅ Yes | ✅ Yes |
| post-receive hook | ✅ Yes | ✅ Yes |
| Run npm install / composer | ⚠️ Limited (server-dependent) | ✅ Full control |
| Docker / Containers | ❌ Not supported | ✅ Yes |
| GitHub Actions self-hosted runner | ❌ Not supported | ✅ Yes |
| Starting price | 500 THB/year | Higher |
For standard PHP, HTML, and CSS websites, Git hook deployment on shared hosting is perfectly sufficient and extremely affordable. For full CI/CD pipelines that include build and test steps, a VPS is a better fit.
Tip: Add a .gitignore file to exclude unnecessary files from being pushed: node_modules/, .env, *.log. This prevents secrets from accidentally ending up on your server.
9. Secure SSH Key Authentication
Using SSH keys instead of passwords is not just more convenient — it is significantly more secure. Keys cannot be brute-forced the way passwords can, and they enable seamless passwordless deployment from your local machine to the hosting server.
Generate an SSH Key Locally
# Generate an Ed25519 key (recommended — fast and secure) ssh-keygen -t ed25519 -C "[email protected]" # Print the public key to copy to your hosting server cat ~/.ssh/id_ed25519.pub
Add the Public Key to Your Hosting Server
# Connect with password for the first time ssh [email protected] # Create the authorized_keys file mkdir -p ~/.ssh && chmod 700 ~/.ssh nano ~/.ssh/authorized_keys # Paste your public key, save, then set permissions chmod 600 ~/.ssh/authorized_keys
After this, SSH connections use the key automatically. Running git push hosting main will deploy without any password prompt, making the workflow faster and suitable for scripted automation.
⚠️ Security reminder: Never commit your private key file (~/.ssh/id_ed25519) to any repository. Keep it only on your local machine and never share it.
10. Multi-Branch Deployments — Development, Staging, Production
Real-world projects typically separate code into multiple environments. You can support this on hosting by modifying the post-receive hook to check which branch was pushed before deciding where to deploy.
#!/bin/bash
# post-receive hook supporting multiple branches
while read oldrev newrev refname; do
BRANCH=$(git rev-parse --symbolic --abbrev-ref "$refname")
if [ "$BRANCH" = "main" ]; then
GIT_WORK_TREE=/home/username/public_html git checkout -f main
echo "Deployed to PRODUCTION: $(date)"
elif [ "$BRANCH" = "staging" ]; then
GIT_WORK_TREE=/home/username/staging git checkout -f staging
echo "Deployed to STAGING: $(date)"
fi
donePushing to main deploys to public_html for live visitors. Pushing to staging deploys to a separate subdirectory, letting you review changes before releasing to production.
| Branch | Deploy Target | Purpose |
|---|---|---|
main | public_html/ | Production — visible to all visitors |
staging | staging/ | Pre-release testing |
develop | dev/ | Active development environment |
11. Adding Rollback to the Hook Script
Every reliable deployment pipeline needs a rollback mechanism. You can add this logic directly to the post-receive hook so that if the deployment fails, the server automatically reverts to the last known good commit.
#!/bin/bash GIT_WORK_TREE=/home/username/public_html export GIT_WORK_TREE GIT_DIR=/home/username/repos/mysite.git export GIT_DIR # Record the current commit before deploying PREV_COMMIT=$(git -C /home/username/public_html rev-parse HEAD 2>/dev/null || echo "none") # Deploy new code if git checkout -f main; then echo "Deploy successful: $(date)" echo "Commit: $(git rev-parse HEAD)" else echo "Deploy failed — rolling back..." git checkout -f "$PREV_COMMIT" echo "Rolled back to $PREV_COMMIT" fi
You should also maintain a deploy log for auditing purposes. Add this line to your hook script:
# Append deploy record to log file
echo "$(date): branch=main commit=$(git rev-parse HEAD)" >> /home/username/deploy.log12. Comparing Deployment Methods on Shared Hosting
Developers use several approaches to deploy code to shared hosting. Each has distinct trade-offs in terms of speed, reliability, and complexity, as shown in the comparison below.
| Method | Ease of Use | Error Risk | Best For |
|---|---|---|---|
| Manual FTP Upload | Low | High (human error) | Complete beginners |
| Git Hook (bare repo) | High | Low | Most PHP/HTML projects |
| PHP Webhook receiver | Very high | Low (if secret set) | Teams using GitHub/GitLab |
| GitHub Actions + SCP | Medium | Low | Projects requiring CI steps |
For small to medium PHP projects, the Git bare repository with a post-receive hook offers the best balance of simplicity and reliability — especially on hosting plans that already support SSH access. The setup takes about 20 minutes and delivers a workflow developers at any skill level can maintain confidently.
Tip: Add a .gitignore file to exclude unnecessary files from being pushed: node_modules/, .env, *.log. This prevents secrets from accidentally ending up on your server.
Hosting with SSH Access for Git Deployment
AsiaGB Hosting starts at 500 THB/year with SSD storage, DirectAdmin, PHP 7.4/8.2/8.3, and SSH access available on request.
View Hosting Plans