Deployments

A release goes live only once it has booted

Every deploy builds beside the running release, checks it can boot, switches over in one move, and puts the previous release straight back if the site stops answering.

A deployment that succeeded: each named step on the left, and the release's own output on the right. A deployment that succeeded: each named step on the left, and the release's own output on the right.
Releases

Nothing being served is touched until the new release is ready

Each deploy fetches into a new directory under releases/, links the shared .env and storage, and runs your deploy script there as the site's own user. Then it boots the release: the autoloader, and for Laravel the whole framework. Only then does current move, and PHP-FPM reloads.

  • A release that cannot boot never goes live, with no downtime at all
  • A real request to the site afterwards; if it fails, the previous release goes straight back
  • Roll back by hand to any release still on disk
A failed deployment that stopped at Check the release can boot, with the error and the steps it skipped. A failed deployment that stopped at Check the release can boot, with the error and the steps it skipped.
Migration review

Risky migrations, read before they run

Before the deploy script runs, the pending migrations are read as text. An index on an existing table, a column added with a default, a changed or dropped column, a new foreign key: each is listed with the live size of the table it touches, and raised when that table is large.

  • Optionally hold a deploy you start by hand until somebody has looked
  • It never runs a migration to find out, and never guesses how long a lock will take
A site's deployments: releases, their outcome, the commit and who or what started each one. A site's deployments: releases, their outcome, the commit and who or what started each one.
shipways.yaml

The repository says what it needs

A shipways.yaml beside composer.json declares the PHP version, extensions, the deploy script, the scheduler, Reverb, Inertia SSR or Octane, daemons and cron entries. Every deploy reads it from the release it just fetched and makes the site match, so the code and the configuration it needs ship in the same pull request.

  • The panel drafts one from what the site runs now, and can open the pull request
  • Pull requests get the plan as a check, before anything merges
  • A deploy never removes anything; removals wait for a person
shipways.yaml
version: 1

php: "8.4"
extensions: [redis, imagick]

deploy: |
  composer install --no-dev --optimize-autoloader
  php artisan migrate --force
  npm ci && npm run build

scheduler: true
reverb: true

daemons:
  - name: horizon
    command: php artisan horizon
    stop_wait_seconds: 90

scheduled_jobs:
  - name: prune
    command: php artisan model:prune
    expression: "0 3 * * *"
01 Site kinds

Sixteen kinds of site, each served the way it expects

The kind decides the nginx, the PHP pool or the Node process, and the default deploy script.

Laravel Symfony PHP WordPress Bedrock Craft CMS Statamic phpMyAdmin Roundcube webmail Next.js Nuxt.js SvelteKit Astro Node.js HTML Proxied to a port
02 Around the deploy

Everything else a site needs to stay up

Source control

GitHub, through a token or the GitHub App, GitLab on gitlab.com or your own instance, and Bitbucket Cloud. Each site gets its own read-only deploy key.

Deploy triggers

By hand, on push, from a deploy hook for CI, from the API, or from your assistant over MCP.

Environment

The .env lives on the server, not in Shipways. Every save keeps the previous version, with who and when.

Domains

Each name shows where it points right now, with the exact record to add when it does not point here.

Certificates

Let's Encrypt, renewed from 30 days out and alerted at 14, or one of your own.

Laravel runtime

Reverb, Inertia SSR and Octane on Swoole, each one switch, with the nginx and daemons written for you.

Maintenance mode

Served by nginx rather than the app, with a bypass link for you while it is up.

Private packages

Composer and npm logins for Nova, Spark or a private registry, written to every server.

Moving a site

To another server, with one short freeze for the last copy, and a way back until you finish.

One machine, free, for as long as you like

No card and no end date. Connect a spare box and watch it provision; everything it builds carries into whichever plan you move to.