Yes. Every site in the panel can be linked to a GitHub repository, public or private. Each push to the branch you choose clones the commit into the site’s container, runs your build script there, and switches the document root to the new release. The full build log stays in the panel.
This replaces the git pull over SSH routine, and it replaces uploading a zip through the file manager. Here is the setup, then the two things the panel does not do for you.
Connect your GitHub account
In the panel sidebar, open GitHub connection and click Connect GitHub. GitHub asks you to confirm, creates a small GitHub App under your account, and then asks which account and which repositories it may read. Grant it the repositories you intend to deploy, not everything.
You do this once per panel login. Every site you own can then pick from those repositories.
Link the site
Open the site, click the GitHub tab, and fill in four fields:
- Repository and branch. A tag works too if you release by tag.
- Build script. The command that turns a fresh clone into a working site. For most projects this is a short shell script committed to the repository, for example
sh build.sh. - Publish directory. The folder the web server should serve.
publicfor Laravel,distorbuildfor a static site, empty for plain PHP. - Auto deploy. On means every push deploys. Off means you press Deploy now when you are ready.
Save, press Deploy now once, and watch the log.
Where the files go
Each deploy clones into deploys/<commit>/ inside your site’s home directory and runs the build script in that folder. When the build finishes, the symlink deploys/current points at the new folder and the site’s document root is set to deploys/current/<publish directory> automatically. You never edit the document root by hand.
Old releases stay on disk, which makes rolling back a matter of redeploying an earlier commit from the history list.
A build script for Laravel
#!/bin/sh
set -e
# ~/shared holds what every release shares: .env and storage
SHARED=../../shared
mkdir -p $SHARED
[ -d $SHARED/storage ] || cp -R storage $SHARED/storage
rm -rf storage
ln -s $SHARED/storage storage
FIRST_DEPLOY=
if [ ! -f $SHARED/.env ]; then
cp .env.example $SHARED/.env
FIRST_DEPLOY=1
fi
ln -sf $SHARED/.env .env
composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader
if [ -n "$FIRST_DEPLOY" ]; then
php artisan key:generate --force --no-interaction
echo "First deploy: fill in ~/shared/.env, then press Deploy now again."
exit 1
fi
php artisan migrate --force
php artisan storage:link
php artisan optimize
php artisan queue:restart
# php artisan horizon:terminate # if you run Horizon
# php artisan reverb:restart # if you run Reverb
Three things are worth reading closely.
Your .env and storage live outside the release
There is no environment variable screen in the panel, and each release is a fresh clone. Anything that is not in git would be lost on the next deploy.
The script keeps those things in ~/shared and links them into every release. .env is one file for all releases. storage/ is one folder too, so uploads, file sessions, file cache and logs survive a deploy, and users stay logged in.
The first deploy creates ~/shared/.env from .env.example, generates the app key, and then stops on purpose, because .env.example has no real database password. Open ~/shared/.env over SSH or in the file manager, fill in the database, mail and APP_URL settings, and press Deploy now again. That deploy runs the migrations and goes live.
To change a setting later, edit ~/shared/.env, then run php artisan config:cache in ~/deploys/current over SSH, or simply deploy again. The build caches the config, so an edit on its own is not picked up.
Any other file that is not in git, such as an SQLite database or a downloaded binary, can live in ~/shared the same way.
Worker processes do not restart on deploy
If the site runs worker processes (a queue worker, Horizon, Reverb, Octane, a Node server), they keep running the old release after a deploy. The panel does not restart them for you.
For Laravel, the last lines of the build script handle most of it, and each tool has its own command:
- Queue workers:
php artisan queue:restart. The worker finishes its current job and exits, and the panel starts it again in the new release. - Horizon:
php artisan horizon:terminate. Horizon ignoresqueue:restart, so without this line it keeps running the old code. - Reverb:
php artisan reverb:restart.
Uncomment the lines for the tools you run.
Two workers do not listen for any of those signals: schedule:work and Octane. For those, press Restart container on the site overview after the deploy. It restarts every worker on the site and takes a few seconds.
Checking a deploy
The GitHub tab lists every deploy with its commit message, who or what triggered it, and a View logs link that opens the build output. A failed build leaves the previous release serving, so a broken push does not take the site down. Fix it and push again.
What this is not
It is not a build farm. The build runs inside your site’s container with the same PHP, Composer, Node and git you get over SSH, and the same resource limits. Compile heavy assets in GitHub Actions and commit or download the result if a build is slow here.
One-click installed WordPress sites cannot be linked to a repository. Create the site empty, then connect it.