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@latestVia 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 versionFor 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/.envComposer / 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 apache2See 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-onlyIf 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 deployYou'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 timestamp7. 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