shipyard

Quickstart

Install Shipyard, write a shipyard.yaml, and run your first deploy in under five minutes.

1. Install

The binary is a single static Go executable. No runtime to install on the server.

Via Go

go install github.com/philiprehberger/shipyard/cli/cmd/shipyard@latest

Via tarball (Linux / macOS)

curl -sSL https://github.com/philiprehberger/shipyard/releases/latest/download/shipyard_linux_amd64.tar.gz \
  | tar -xz
sudo mv shipyard /usr/local/bin/
shipyard version

For Apple Silicon use shipyard_darwin_arm64.tar.gz; for Windows download the .zip from the releases page.

2. Prepare the server

Shipyard expects a release-root directory it owns. SSH in once and create it:

ssh ubuntu@my-server.example.com
sudo mkdir -p /var/www/my-app/{releases,shared,_incoming}
sudo chown -R ubuntu:ubuntu /var/www/my-app

# Put any files that must persist across deploys (e.g. .env) into shared/:
echo "APP_KEY=base64:..." > /var/www/my-app/shared/.env

Composer / npm on the server is not required. Shipyard builds the artifact locally and ships it. The server only needs tar or unzip, which every Linux distro has.

3. Write shipyard.yaml

Drop a config at the root of your project. The minimum:

app: my-app

host:
  ssh: ubuntu@my-server.example.com
  identity_file: ~/.ssh/id_ed25519
  release_root: /var/www/my-app

artifact:
  source: ./build/release.tar.gz
  format: tar.gz

shared:
  files: [.env]

health_check:
  url: https://my-app.example.com/healthz
  expect: "healthy"
  retries: 10
  delay: 3s

hooks:
  pre_upload:
    - npm ci
    - npm run build
    - tar -czf build/release.tar.gz -C dist .
  post_flip:
    - sudo systemctl reload apache2
  on_rollback:
    - sudo systemctl reload apache2

See the config reference for every field. The examples directory has full configs for Laravel, Next.js, and a Laravel + supervisor queue.

4. Validate

Before you ship anything, lint the config:

shipyard doctor --config-only

If anything's wrong, doctor surfaces every issue in one pass with the exact YAML field that broke. Strict mode catches typos like health-check vs. health_check at load time.

5. Deploy

shipyard deploy

You'll see a pretty stream of phases ([connect], [upload], [extract], [post-extract], [flip], [post-flip], [health], [prune], [done]) plus full structured JSON on stderr for scripting / log shipping.

If the health check fails, Shipyard flips the symlink back to the previous release, runs on_rollback, releases the lock, and exits with code 4. Your app stays serving requests on the old release the entire time.

6. Rolling back manually

If a deploy passed the health check but you still want to revert (a bug that takes longer than the probe window to surface):

shipyard rollback                    # → previous release
shipyard rollback --to 20260610190921   # → a specific timestamp

7. Inspecting state

shipyard status      # current release, all releases, lock state
shipyard releases    # list of timestamps newest-first
shipyard prune --dry-run   # show what auto-prune would delete

→ Config reference · → CLI reference