Appearance
Running Shiphook as a systemd service
After HTTPS + nginx are set up, you’ll usually want Shiphook to run in the background, survive SSH disconnects, and start on boot. On most modern Linux distros (including AlmaLinux), use systemd.
The automated shiphook setup-https script (and interactive shiphook when you answer y to HTTPS) creates a per-domain unit at /etc/systemd/system/shiphook-<domain>.service (long domains are safely truncated+hashed), reloads systemd, and runs systemctl enable --now <unit>.service when systemd is available and the CLI passes the install path (normal sudo flow).
If the unit already exists, setup-https leaves it unchanged by default so re-running setup does not reinstall the service. To force reinstall/restart from setup, set SHIPHOOK_REINSTALL_SYSTEMD=1.
To avoid accidental duplicates, setup-https also checks for an existing unit that already uses the same WorkingDirectory (same repo path). If found, it skips creating another unit name for that repo unless you force reinstall.
If a Shiphook unit is already active, running shiphook again from an interactive terminal will restart/start the default service workflow.
When systemd starts Shiphook, the CLI won't try to restart it again (avoids restart loops). Running shiphook manually from an interactive terminal can restart the unit so the service comes up with updated config.
Example service unit
Assuming:
- Your repo lives at
/srv/my-app(replace with your repo path) - You want the default Shiphook port (
3141) and path (/)
Create /etc/systemd/system/shiphook.service as root:
ini
[Unit]
Description=Shiphook deploy webhook
After=network.target
[Service]
Type=simple
WorkingDirectory=/srv/my-app
ExecStart=/usr/bin/env shiphook
Restart=on-failure
RestartSec=5s
# Optional: environment overrides
Environment=SHIPHOOK_PORT=3141
# Environment=SHIPHOOK_PATH=/webhook
# Environment=SHIPHOOK_RUN_SCRIPT=npm run deploy
[Install]
WantedBy=multi-user.targetThen reload and start:
bash
sudo systemctl daemon-reload
sudo systemctl enable --now shiphook.service
sudo systemctl status shiphook.serviceShiphook now:
- Runs in the background
- Starts on boot
- Is proxied by nginx+Certbot on HTTPS (from the HTTPS setup docs)
Notes
Set WorkingDirectory to the repo where Shiphook should run (and where
shiphook.yamllives). This is usually the same directory youcdinto before runningshiphookmanually.Create a non-privileged user for the service (for example,
shiphook) and ensure that repo directory is owned/readable by that user:bashsudo useradd --system --shell /usr/sbin/nologin --home /nonexistent shiphook sudo chown -R shiphook:shiphook /srv/my-appUse
journalctl -u shiphook.serviceto inspect logs (including deploys and secrets setup).You can still run
shiphook deploymanually to trigger one-off deploys; it doesn’t interfere with the service.
One service, multiple apps/domains
You can run either one process for many apps (recommended) or one service per app/domain:
- Single process mode: one unit with
apps:config handles many repos/domains. - Per-app mode: one
shiphook-<domain>.serviceper repo/domain, each on its own port.
shiphook.service (or a custom unit name) can run a single Shiphook process that serves multiple apps via apps: config. This is the recommended way to host multiple repos/domains on one server:
- one
shiphook.service - one Shiphook process
- multiple app routes (
host+path) - one secret per app
Different apps can deploy concurrently; deploys for the same app are serialized.
Cleanup helper (development/troubleshooting)
During webhook/CD setup iterations, stale nginx blocks and old Shiphook unit files are a common source of 404/405/502 surprises. Use:
bash
# Remove Shiphook-managed entries for one domain
# (matching nginx files + matching shiphook*.service units for that domain)
shiphook cleanup --domain shiphook.example.com
# Remove all Shiphook-managed nginx/systemd entries
shiphook cleanup --allThe command creates a timestamped nginx backup before changing files.