Why CloudPanel Deployments Need Automation
CloudPanel is one of the best free server management panels available for self-hosted PHP applications. It provides a clean UI for managing sites, SSL certificates, databases, cron jobs, and vhosts without the complexity or cost of cPanel or Plesk. Many Laravel developers run their client sites on CloudPanel-managed VPS instances.
But CloudPanel has a deployment gap. Unlike platform-specific services such as Laravel Forge, Vapor, or Heroku, CloudPanel provides no native deployment pipeline. Releasing code to a CloudPanel server means:
- SSH-ing in manually and running
git pull && composer install && php artisan migrate - Writing a custom deploy script and triggering it via webhook or cron
- Using a general-purpose deployment tool like Deployer.php and configuring it for CloudPanel specifics
- Paying for a separate deployment service like Envoyer or Buddy.Works
CloudPanel Deploy Action takes a different approach: a purpose-built GitHub Action that knows about CloudPanel's specific deployment needs and handles them automatically as part of your CI/CD pipeline.
Prerequisites
Before setting up the action, you need:
- A CloudPanel-managed server with SSH access enabled
- A GitHub repository containing your application
- An SSH key pair — the private key will be stored as a GitHub Secret, the public key added to the server
Setting Up SSH Access
Generate a dedicated deployment key pair on your local machine:
ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/cloudpanel_deploy
Add the public key to your server's ~/.ssh/authorized_keys:
cat ~/.ssh/cloudpanel_deploy.pub | ssh user@your-server 'cat >> ~/.ssh/authorized_keys'
In your GitHub repository, go to Settings → Secrets and variables → Actions and add:
| Secret Name | Value |
|---|---|
DEPLOY_HOST |
Your server's IP address or hostname |
DEPLOY_USER |
SSH username (usually your CloudPanel site username) |
DEPLOY_KEY |
Contents of ~/.ssh/cloudpanel_deploy (private key) |
DEPLOY_PATH |
Absolute path to your application on the server |
Basic Laravel Deployment Workflow
Create .github/workflows/deploy.yml in your repository:
name: Deploy to CloudPanel
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run tests
run: |
composer install --no-interaction --prefer-dist
cp .env.example .env
php artisan key:generate
php artisan test
- name: Deploy to CloudPanel
uses: amjadiqbal/cloudpanel-deploy-action@v1
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
deploy-path: ${{ secrets.DEPLOY_PATH }}
app-type: laravel
php-version: '8.3'
With this workflow, every push to main will:
- Run your test suite
- Deploy to the server only if all tests pass
- Execute the full Laravel deployment sequence automatically
What the Laravel Deployment Step Executes
For app-type: laravel, the action runs the following commands on the server:
cd /path/to/app
# Pull latest code
git pull origin main
# Install/update dependencies
composer install --no-interaction --prefer-dist --optimize-autoloader --no-dev
# Run database migrations
php artisan migrate --force
# Clear and rebuild caches
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
# Restart queue workers
php artisan queue:restart
# Reload PHP-FPM (CloudPanel-specific)
clpctl service:reload php-fpm
All of these steps are configurable. If you use a deployment script (./deploy.sh) instead of the default steps, set custom-script: true and the action will execute your script rather than the built-in sequence.
Node.js Application Deployment
For a Next.js or Node.js API on a CloudPanel server:
- name: Deploy to CloudPanel
uses: amjadiqbal/cloudpanel-deploy-action@v1
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
deploy-path: ${{ secrets.DEPLOY_PATH }}
app-type: nodejs
node-version: '20'
pm2-process: my-nextjs-app
For Node.js apps, the action runs npm ci && npm run build and then reloads the PM2 process.
Zero-Downtime Deployments
The default deployment sequence does not guarantee zero downtime — there is a window between git pull and php artisan migrate where the running code may not match the deployed database schema.
For zero-downtime deployments, use the maintenance-mode: true option:
with:
maintenance-mode: true
This wraps the deployment in php artisan down and php artisan up calls. For applications that need true zero-downtime (no maintenance mode), configure a before-deploy hook to switch a symlink, following the atomic deployment pattern.
Deployment Notifications
The action can post deployment notifications to Slack or Discord:
- name: Deploy to CloudPanel
uses: amjadiqbal/cloudpanel-deploy-action@v1
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
deploy-path: ${{ secrets.DEPLOY_PATH }}
app-type: laravel
notify-slack: ${{ secrets.SLACK_WEBHOOK_URL }}
GitHub Repository
Full configuration documentation, all available options, and example workflow files are on GitHub and available on the GitHub Actions Marketplace.
Conclusion
Professional CI/CD pipelines are not just for teams using managed hosting. If you run your own CloudPanel server — which many Laravel developers do — you deserve the same deployment automation that Forge or Vapor users take for granted. CloudPanel Deploy Action brings that automation to any CloudPanel server in under five minutes of configuration.
Gate your deployments behind automated test suites. Stop SSH-ing into servers to deploy code. Let GitHub Actions handle it.