Skip to content

Webhook setup

Shiphook is triggered by an HTTP POST to its URL. You configure your Git host (or any service) to send that POST when you push. No special payload format is required — Shiphook only cares that the request is POST and that a secret is sent.

In multi-app mode (apps:), Shiphook first matches app route by Host + path and then validates that matched app's secret. Keys are isolated per app/repo. If an app secret is omitted in config, Shiphook generates and persists one for that app on startup.

GitHub requires a public HTTPS URL. Put nginx (or another reverse proxy) and TLS in front of Shiphook; see HTTPS (nginx + Certbot).


What Shiphook expects

  • Method: POST
  • URL: Your Shiphook base URL + path (e.g. http://your-server:3141/ or http://your-server:3141/webhook if you set path: /webhook in shiphook.yaml or SHIPHOOK_PATH=/webhook)
  • Auth (required): Include the secret in one of:
    • Header: X-Shiphook-Secret: <secret>
    • Header: Authorization: Bearer <secret>

Shiphook does not validate payload content (e.g. GitHub payload). It runs git pull and the run script on every authorized POST.

Multi-app routing/auth example

yaml
apps:
  - name: app-a
    host: app-a.example.com
    path: /deploy
    repoPath: /srv/app-a
    runScript: npm run deploy
    secret: app-a-secret
  - name: app-b
    host: app-b.example.com
    path: /deploy
    repoPath: /srv/app-b
    runScript: npm run deploy
    secret: app-b-secret

With this config:

  • https://app-a.example.com/deploy only accepts app-a-secret
  • https://app-b.example.com/deploy only accepts app-b-secret
  • app-a-secret cannot deploy app B (and vice versa)

Logs

For each authorized POST, Shiphook runs the deploy and writes logs into .shiphook/logs/:

  • .shiphook/logs/<UTC-date>_<id>.json
  • .shiphook/logs/<UTC-date>_<id>.log

The filename stem is YYYY-MM-DD_HH-mm-ssZ (UTC) plus _ and a UUID so listings sort by time and stay unique.

By default, Shiphook streams deploy output back to the HTTP client (plain text) and finishes with a final line like:

[done] ok=true exitCode=0

If you need the old buffered JSON response, use ?format=json (the JSON includes log: { id, json, log }).


GitHub

  1. Open your repo → SettingsWebhooksAdd webhook.
  2. Payload URL: Your public HTTPS URL (e.g. https://deploy.example.com/ or https://deploy.example.com/webhook). Use HTTPS setup; Shiphook usually stays on http://127.0.0.1:3141 behind nginx.
  3. Content type: application/json.
  4. Secret: Use the same value as SHIPHOOK_SECRET (or the value from .shiphook.secret) so only GitHub can trigger the deploy.
  5. Which events: “Just the push event” is enough.
  6. Save.

On every push, GitHub sends a POST to that URL. Shiphook runs git pull and your run script.


GitHub Actions (live streaming)

When Shiphook receives the webhook, it streams git pull + your deploy script output back to the HTTP response.

To see it live in the GitHub Actions step log:

  1. Trigger Shiphook with curl -N (no curl buffering).
  2. Optionally capture the output and check the final [done] ... line so the job fails if deploy fails.

Minimal shiphook.yaml (server-side config):

yaml
secret: your-secret
runScript: npm run deploy

Minimal GitHub Actions workflow example (.github/workflows/deploy.yml):

yaml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Shiphook webhook (streaming)
        env:
          SHIPHOOK_SECRET: ${{ secrets.SHIPHOOK_SECRET }}
          SHIPHOOK_URL: ${{ secrets.SHIPHOOK_URL }} # optional (defaults to https://shiphook.majico.xyz)
        run: |
          BASE="${SHIPHOOK_URL:-https://shiphook.majico.xyz}"
          BASE="${BASE%/}"

          LOG_FILE="$(mktemp)"
          curl -N -S -X POST "${BASE}/" \
            -H "X-Shiphook-Secret: ${SHIPHOOK_SECRET}" \
            -H "Content-Type: application/json" \
            -d '{}' 2>&1 | tee "${LOG_FILE}"

          DONE_LINE="$(tail -n 1 "${LOG_FILE}")"
          echo "Final line: ${DONE_LINE}"
          echo "${DONE_LINE}" | grep -q '\[done\] ok=true' || exit 1

GitLab

  1. Open your repo → SettingsWebhooks.
  2. URL: Your Shiphook URL.
  3. Secret token: Same value as SHIPHOOK_SECRET (or the value from .shiphook.secret).
  4. Trigger: Push events.
  5. Add webhook.

Generic: any HTTP client

Any service that can send an HTTP POST works. Example with curl:

bash
curl -X POST http://your-server:3141/ \
  -H "X-Shiphook-Secret: your-secret"

You can send the secret via either header:

bash
# Header: X-Shiphook-Secret
curl -X POST http://your-server:3141/ \
  -H "X-Shiphook-Secret: your-secret"

Or:

bash
# Header: Authorization: Bearer <secret>
curl -X POST http://your-server:3141/ \
  -H "Authorization: Bearer your-secret"

What Shiphook returns

Shiphook returns:

  • HTTP 200 for valid authenticated requests (valid secret)
  • HTTP 401 for missing/invalid secrets

For successful requests (HTTP 200):

  • Default: streaming plain text output ending with [done] ok=... exitCode=...
  • Opt-out JSON: use ?format=json for the old buffered JSON response

For HTTP 401, the response is still JSON.

Success JSON (?format=json, run script exited 0):

json
{
  "ok": true,
  "pull": {
    "success": true,
    "stdout": "...",
    "stderr": ""
  },
  "run": {
    "stdout": "...",
    "stderr": "",
    "exitCode": 0
  },
  "error": null
}

Failure JSON (?format=json, run script exited non-zero):

json
{
  "ok": false,
  "pull": { "success": true, "stdout": "...", "stderr": "" },
  "run": {
    "stdout": "...",
    "stderr": "...",
    "exitCode": 1
  },
  "error": null
}
  • ok: true only when the run script exit code is 0.
  • pull.success: true if git pull completed without throwing (e.g. no remote is still a “success” for pull; run script still runs).
  • run.exitCode: exit code of the run script, or null if the process could not be started.
  • error: set if something went wrong (e.g. pull threw, or run process failed to start).

Use this response for monitoring or alerting (e.g. from GitHub Actions, Uptime Robot, or your own scripts). Non-200 status codes: 404 for wrong method/path, 401 when a secret is required and missing or wrong.