SpipCP
Deploys

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 through

A 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 install errors) → 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.

On this page