Config reference
Every field in shipyard.yaml. Required fields are flagged; everything else has a sensible default.
Strict mode. Unknown fields are rejected at load time. Misspell health_check as health-check and the deploy refuses to start with the exact YAML line that caused it.
app (required)
app: webhook-relayShort slug used in log lines and as the default lock-path component. Lowercase alphanumerics with - or _ only. Up to 63 chars.
host (required)
host:
ssh: ubuntu@1.2.3.4
identity_file: ~/.ssh/id_ed25519
release_root: /var/www/webhook-relay| Field | Required | Notes |
|---|---|---|
ssh | yes | user@host[:port]. Port defaults to 22. IPv6 supported via user@[::1]:port. |
identity_file | yes | Path to private key. ~/ is expanded. Encrypted keys are not supported in v0.1 — decrypt with ssh-keygen -p first. |
release_root | yes | Absolute path on remote. Must be writable by the SSH user. |
artifact (required)
artifact:
source: ./build/release.tar.gz
format: tar.gz| Field | Required | Notes |
|---|---|---|
source | yes | Local path to the build artifact. Relative paths resolve against the directory of the config file, not the shell’s cwd. |
format | auto | zip or tar.gz. Inferred from the source extension if omitted. |
releases
releases:
keep: 5Auto-prune retains the most recent keep releases plus the current symlink target (if different). Default 5. Cannot be less than 1.
shared
shared:
files:
- .env
dirs:
- storage
- bootstrap/cacheAt deploy time, every entry under shared.files and shared.dirs is symlinked from the release dir back to shared/. Use this for anything that must persist between releases (.env, Laravel storage/, uploaded media).
Paths are relative to the release directory. Absolute paths are rejected. If a shared.files target doesn’t exist on the remote when the deploy runs, the deploy fails fast with an actionable message (no silently-created empty .env).
health_check
health_check:
url: https://my-app.example.com/healthz
expect: "healthy"
status: 200
retries: 10
delay: 3s
timeout: 5s| Field | Default | Notes |
|---|---|---|
url | required if block present | Must start with http:// or https://. |
expect | empty | Substring that must appear in the body. Empty = status check only. |
status | 200 | HTTP status that counts as healthy. |
retries | 10 | Number of attempts. Total wall time ≈ retries × (delay + timeout). |
delay | 3s | Wait between attempts. 3s, 500ms, 1m all parse. |
timeout | 5s | Per-request timeout. |
If the whole health_check block is omitted, the deploy flips and exits without probing. --skip-health on the deploy command does the same per-invocation — use it sparingly.
Redirects are not followed. Point the URL at the final destination directly. The deploy log surfaces every attempt’s status code so a flapping probe is immediately diagnosable.
hooks
hooks:
pre_upload:
- composer install --no-dev --optimize-autoloader
- npm run build
post_extract:
- php artisan migrate --force
- php artisan config:cache
post_flip:
- sudo systemctl reload apache2
on_rollback:
- sudo systemctl reload apache2| Phase | Where | Cwd | What it’s for |
|---|---|---|---|
pre_upload | local | your shell’s cwd | Build the artifact. |
post_extract | remote | the new release dir | Migrations, cache warming. Runs before the flip — if it fails, the release dir is deleted and the current symlink never moves. |
post_flip | remote | current/ | Reload the web server / restart workers. Runs after the flip — if it fails, Shipyard rolls back automatically. |
on_rollback | remote | current/ | Cleanup or notification after a rollback (health-fail or post-flip-fail). |
Each entry is passed to sh -c on the relevant side. Quotes are linted for balance at load time — an unterminated string is rejected before the deploy starts.
lock
lock:
enabled: true
path: /var/www/webhook-relay/shared/.shipyard.lock
ttl: 10m| Field | Default | Notes |
|---|---|---|
enabled | true | Set false only if you’re certain about concurrency. |
path | <release_root>/shared/.shipyard.lock | Absolute path. Must be writable by the SSH user. |
ttl | 10m | Stale-lock threshold. Minimum 30s. A lock older than ttl is stolen automatically (logged loudly) so a crashed deploy can’t block forever. |
Implementation: SFTP O_CREATE|O_EXCL on a small JSON file containing local user, hostname, PID, and acquired-at timestamp. shipyard status displays the holder.