Git deploys
Deploy a site from git — scoped deploy keys, the fetch→build→release pipeline, zero-downtime cutover, one-click rollback, and push-triggered redeploys.
A php, static, or node site can deploy straight from a git repository. You connect a repo, the panel generates a scoped deploy key, and every deploy runs the same pipeline: fetch → build → stage a release → smoke-check → cutover. A bad build never touches the live site, and any deploy is one click away from rollback.
Connecting a git source
On the site workspace's Deploys tab, set the repository. You can connect a git account to browse your repos and branches and register the deploy key in one click, or paste a clone URL by hand — both reach the same pipeline below. Either way, set:
- Repository URL — the SSH clone URL (
git@host:owner/repo.git) for a private repo, or any clone URL for a public one. - Branch — the branch deploys track (e.g.
main). - Deploy key — for a private repo, the panel generates a deploy key scoped to this site
only. Its name defaults to
<site>-deploy(rename it before generating if you like). Copy the public half and add it as a deploy key on the repository (not an account key). The private half is encrypted at rest and never leaves the panel.
Per-repo keys, never broad tokens
Each site gets its own deploy key, scoped to its one repo. A key can't fetch another site's repo. A broad provider token (a personal access token, an org token) is never stored and never reaches a node — the per-repo deploy key is the only credential. Revoking a key makes the next deploy fail with a clear message until you generate a new one.
The release layout
Inside the instance, under the site root:
releases/<timestamp>/ one immutable release (the fetched + built tree)
shared/ state that survives a deploy: uploads, the env file
current -> releases/… the symlink the web server serves throughA deploy builds a new releases/<timestamp> tree, links the shared uploads/env into it,
smoke-checks it, and only then flips current to it in one atomic move. Because the cutover is a
single swap, a request in flight during a deploy sees either the old release or the new one —
never a broken half-state. Old releases are kept for rollback (the oldest beyond the retention limit
are pruned).
Rollback
The Deploys tab shows every deploy (who, what, when, sha, duration, log). Roll back flips
current back to the previous release — and re-runs the smoke check on it before serving, so a
rollback is as health-gated as a forward deploy. It's just as fast (no re-fetch, no rebuild — the
release is already on disk).
Failure gating
Any failing step aborts before cutover, so the site keeps serving its current release:
- a build failure (e.g.
composer installerrors) → the deploy is marked failed with the failing step + a remedy; the new release is discarded; - a smoke-check failure (the new release doesn't serve) → same, no cutover;
- a failing migration hook (a blueprint-declared pre/post step like
php artisan migrate) → same, the release never goes live.
In every case the deploy history names the failing step and what to fix.
Webhooks
A site can redeploy automatically on every push — see Deploy from GitHub. Each site has its own webhook endpoint and secret. Deliveries are signature-verified, rate limited, and serialized — a push during a running deploy queues exactly one follow-up, so the final state is always the latest commit.
DNSSEC
What DNSSEC is and why it matters, turning it on for a self-hosted zone, the DS-record step at the registrar (and verify DS), key rollover, and the one critical warning — pull the DS at the registrar BEFORE removing DNSSEC, or the zone goes BOGUS.
Deploy from GitHub
Wire a GitHub (or GitLab / Gitea) push to an automatic, health-gated deploy in a few minutes — generate a deploy key, add the webhook, push.