Install Shipyard on a Raspberry Pi
Shipyard is one static binary and one SQLite file. A Raspberry Pi 4 or 5 runs it comfortably.
What you need
- Raspberry Pi 4 or 5 with 64-bit Raspberry Pi OS or Ubuntu Server
- An SSD or a good SD card — the queue and logs are written to local disk
- SSH access with
sudo
1. Install the binary
Take shipyard-linux-arm64 from Downloads (shipyard-linux-armv7 on a 32-bit system) and copy it to the Pi:
scp shipyard-linux-arm64 pi@raspberrypi.local:/tmp/shipyard
ssh pi@raspberrypi.local
sudo install -m 0755 /tmp/shipyard /usr/local/bin/shipyard
2. Create the service user
sudo useradd --system --home-dir /var/lib/shipyard --shell /usr/sbin/nologin shipyard
sudo install -d -m 0750 -o root -g shipyard /etc/shipyard
3. Write the configuration
/etc/shipyard/.shipyard.yaml:
listen: 127.0.0.1:8080
projects:
- id: my-app
repository: you/my-app
enabled: true
issue_label: agent-ready
release_interval: 48h
content:
interval: 168h
publish_mode: pull_request
storage:
path: /var/lib/shipyard/shipyard.db
logging:
directory: /var/lib/shipyard/logs
runtime:
embedded_worker: true
api_token_env: SHIPYARD_API_TOKEN
observability:
metrics: true
pipelines:
project-check:
steps:
- id: config
type: diagnostic
timeout: 30s
4. Set the API token
echo "SHIPYARD_API_TOKEN=$(openssl rand -hex 32)" | sudo tee /etc/shipyard/shipyard.env > /dev/null
sudo chown root:shipyard /etc/shipyard/shipyard.env /etc/shipyard/.shipyard.yaml
sudo chmod 0640 /etc/shipyard/shipyard.env /etc/shipyard/.shipyard.yaml
5. Add the systemd unit
/etc/systemd/system/shipyard.service:
[Unit]
Description=Shipyard portfolio control plane
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=shipyard
Group=shipyard
WorkingDirectory=/var/lib/shipyard
StateDirectory=shipyard
StateDirectoryMode=0750
EnvironmentFile=-/etc/shipyard/shipyard.env
ExecStart=/usr/local/bin/shipyard -config /etc/shipyard/.shipyard.yaml
Restart=on-failure
RestartSec=5s
TimeoutStopSec=15s
SyslogIdentifier=shipyard
UMask=0077
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now shipyard
6. Check it
curl http://127.0.0.1:8080/healthz
curl http://127.0.0.1:8080/readyz
journalctl -u shipyard -f
7. Run the first pipeline
TOKEN=$(sudo sed -n 's/^SHIPYARD_API_TOKEN=//p' /etc/shipyard/shipyard.env)
curl -X POST http://127.0.0.1:8080/api/v1/runs \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: pi-first-check-001' \
-d '{"project_id":"my-app","kind":"pipeline","task":"project-check","input":""}'
The run goes through the queue, the embedded worker picks it up and the result is in the run list:
curl -H "Authorization: Bearer $TOKEN" "http://127.0.0.1:8080/api/v1/runs?limit=1"
Open the UI from your laptop
Shipyard listens on loopback. Tunnel it:
ssh -L 8080:127.0.0.1:8080 pi@raspberrypi.local
Then open http://127.0.0.1:8080 and paste the token.
Keep the SD card alive
Cap the journal in /etc/systemd/journald.conf:
SystemMaxUse=200M
Shipyard's own log and run retention is set under retention: in the configuration.