{"id":47599299,"url":"https://github.com/cap-jmk-real/shiphook","last_synced_at":"2026-04-01T18:37:13.488Z","repository":{"id":341194442,"uuid":"1169249273","full_name":"cap-jmk-real/shiphook","owner":"cap-jmk-real","description":"Ship on hook. Webhook → git pull → run your deploy script. Configure via shiphook.yaml or env. Self-hosted ideal for indie devs and micro-SaaS.","archived":false,"fork":false,"pushed_at":"2026-03-18T18:42:40.000Z","size":172,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-19T07:14:24.747Z","etag":null,"topics":["automation","deployment","developer-tools","self-hosted","webhook"],"latest_commit_sha":null,"homepage":"https://cap-jmk-real.github.io/shiphook/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cap-jmk-real.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-28T11:56:12.000Z","updated_at":"2026-03-18T18:46:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cap-jmk-real/shiphook","commit_stats":null,"previous_names":["cap-jmk-real/shiphook"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/cap-jmk-real/shiphook","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cap-jmk-real%2Fshiphook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cap-jmk-real%2Fshiphook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cap-jmk-real%2Fshiphook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cap-jmk-real%2Fshiphook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cap-jmk-real","download_url":"https://codeload.github.com/cap-jmk-real/shiphook/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cap-jmk-real%2Fshiphook/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290911,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","deployment","developer-tools","self-hosted","webhook"],"created_at":"2026-04-01T18:37:12.612Z","updated_at":"2026-04-01T18:37:13.475Z","avatar_url":"https://github.com/cap-jmk-real.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Shiphook\n\n**Self-hosted deploys from Git webhooks** — receive a signed POST, run `git pull`, then run your deploy command. No third-party deploy product: your server, your repo, your script.\n\nShiphook is aimed at **indie projects**, **small SaaS**, and **open source** teams who want something simple they can read and own.\n\n[![CI](https://img.shields.io/github/actions/workflow/status/cap-jmk-real/shiphook/ci.yml?style=flat-square\u0026label=CI)](https://github.com/cap-jmk-real/shiphook/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/shiphook.svg?style=flat-square)](https://www.npmjs.com/package/shiphook)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-3178C6?style=flat-square\u0026logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org/)\n[![Node](https://img.shields.io/badge/Node-22%2B-339933?style=flat-square\u0026logo=node.js\u0026logoColor=white)](https://nodejs.org/)\n[![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-0ea5e9?style=flat-square\u0026logo=readthedocs\u0026logoColor=white)](https://cap-jmk-real.github.io/shiphook/)\n[![CodeRabbit Reviews](https://img.shields.io/coderabbit/prs/github/cap-jmk-real/shiphook?style=flat-square\u0026utm_source=oss\u0026utm_medium=github\u0026utm_campaign=cap-jmk-real%2Fshiphook\u0026labelColor=171717\u0026color=FF570A\u0026link=https%3A%2F%2Fcoderabbit.ai\u0026label=CodeRabbit+Reviews)](https://coderabbit.ai)\n\n---\n\n## What it does\n\n1. You run the Shiphook HTTP server in (or next to) your app repo.\n2. Your Git host sends a webhook when you push.\n3. Shiphook routes the request by host/path, verifies the matched app secret, runs **`git pull`**, reloads **`shiphook.yaml` from the repo when it lives in that tree**, and runs your **`runScript`** (build, restart containers, etc.).\n4. Output can stream back in the HTTP response (useful for GitHub Actions logs) or as JSON (`?format=json`).\n\nConfiguration is **`shiphook.yaml`** in the repo and/or **environment variables** (env wins on conflicts).\n\n---\n\n## Install\n\n```bash\nnpm install -g shiphook\n```\n\nRequires **Node 22+**.\n\n---\n\n## Run the server\n\n```bash\ncd /path/to/your/repo\nshiphook\n```\n\nDefault listen port: **3141**. Trigger a deploy:\n\n```bash\ncurl -X POST http://localhost:3141/\n```\n\nSend the webhook secret as **`X-Shiphook-Secret`** or **`Authorization: Bearer …`** (see [Configuration](#configuration-yaml-or-environment)).\n\n---\n\n## Manual deploy (no webhook)\n\n```bash\nshiphook deploy\n```\n\nSame flow as a webhook: `git pull`, then your script.\n\n---\n\n## CLI\n\n| Command | Purpose |\n|--------|---------|\n| `shiphook` | Start the server (or systemd integration on Linux — see docs). |\n| `shiphook deploy` | Run one deploy in the foreground. |\n| `shiphook cleanup --domain \u003chost\u003e \\| --all` | Linux cleanup helper for Shiphook nginx/systemd state (with backup). |\n| `shiphook version` | Print version (`-v` / `--version` also work). |\n| `shiphook setup-https` | Linux helper for nginx + Let’s Encrypt (GitHub needs HTTPS). |\n\n---\n\n## Logs\n\nEach deploy writes files under **`.shiphook/logs/`**:\n\n- **`\u003cUTC-date\u003e_\u003cid\u003e.json`** — structured log for tools.\n- **`\u003cUTC-date\u003e_\u003cid\u003e.log`** — human-readable.\n\nWith **`?format=json`**, the HTTP body includes `log: { id, json, log }` so you can open the matching files.\n\n---\n\n## HTTPS (GitHub and most hosts)\n\nHosts expect a **public HTTPS** URL. Shiphook speaks HTTP on localhost; put **nginx** (or similar) and **Let’s Encrypt** in front.\n\nOn **Linux**, run **`shiphook setup-https`** or say **`y`** the first time you start `shiphook` in a TTY — the installer can install packages, configure nginx, obtain certs, and install a **systemd** unit. Details: [HTTPS setup](https://cap-jmk-real.github.io/shiphook/self-hosted-https.html).\n\nFor servers without a TTY, set **`SHIPHOOK_SKIP_HTTPS_PROMPT=1`**.\n\n---\n\n## Multi-app on one server\n\nShiphook supports two deployment models on one host:\n\n- **Single process, multi-app (recommended):** one `shiphook` process with one `shiphook.yaml` that uses `apps:` and routes by `host + path`.\n- **Per-app process:** one repo + service per app/domain (often one local port per app).\n\nThe first model is usually easier to operate in production. The second model is useful while iterating on individual app pipelines.\n\n---\n\n## Cleanup during pipeline development\n\nWhile iterating on webhook/CD setup, it is common to accumulate stale nginx/server blocks or old systemd units. Use the built-in cleanup command before re-running setup:\n\n```bash\n# remove configs for one webhook domain (matching nginx files and systemd units)\nshiphook cleanup --domain shiphook.example.com\n\n# or remove all Shiphook-managed nginx/systemd entries\nshiphook cleanup --all\n```\n\nThe cleanup command creates a timestamped nginx backup before applying changes.\n\n---\n\n## Configuration (YAML or environment)\n\nAdd **`shiphook.yaml`** (see [shiphook.example.yaml](shiphook.example.yaml)) or use env vars. **Env overrides the file.**\n\n| Option | Default | Notes |\n|--------|---------|--------|\n| `port` / `SHIPHOOK_PORT` | `3141` | Listen port. |\n| `repoPath` / `SHIPHOOK_REPO_PATH` | current directory | Where `git pull` and the script run. |\n| `runScript` / `SHIPHOOK_RUN_SCRIPT` | `npm run deploy` | Command after pull. |\n| `secret` / `SHIPHOOK_SECRET` | (generated) | Required. Omit in YAML and the CLI can create **`.shiphook.secret`**. |\n| `path` / `SHIPHOOK_PATH` | `/` | URL path for the webhook (e.g. `/deploy`). |\n\nAfter **`git pull`**, Shiphook reloads **repo-local** YAML when the config file lives **inside** the repo. Paths set with **`SHIPHOOK_CONFIG`** to **outside** the repo (e.g. `/etc/...`) are not re-read after pull—use repo-local config if you want each push to pick up YAML changes automatically.\n\nMulti-app mode is supported via `apps:` in `shiphook.yaml` (one process, one systemd service, multiple repos/domains). Each app defines its own `host`, `path`, `repoPath`, and `runScript`; if app `secret` is omitted, Shiphook auto-generates and persists a per-app secret file on first run. Requests for different apps run concurrently, while requests for the same app are serialized.\n\nFull reference: **[Documentation](https://cap-jmk-real.github.io/shiphook/)**\n\nNeed step-by-step deployment examples? See **[Deployment recipes](https://cap-jmk-real.github.io/shiphook/deployment-recipes.html)** for single-app and multi-app on one server (DNS, GitHub Actions, secrets, server commands, and YAML).\n\n---\n\n## GitHub webhook (quick)\n\n1. Repo → **Settings** → **Webhooks** → **Add webhook**.\n2. **Payload URL:** your HTTPS URL (path must match `SHIPHOOK_PATH`).\n3. **Content type:** `application/json`.\n4. **Secret:** same as your Shiphook secret.\n5. **Events:** e.g. **Just the push event**.\n\n---\n\n## Why Shiphook?\n\n- **No vendor lock-in** — no deploy SaaS account; you control the box and the script.\n- **Small surface** — one Node process, YAML or env, secret-based auth.\n- **Fits real stacks** — `npm run deploy`, Docker, shell, whatever you already use.\n\n---\n\n## Programmatic use\n\n```ts\nimport { createShiphookServer, ensureWebhookSecret, loadConfig } from \"shiphook\";\n\nconst config = loadConfig();\nawait ensureWebhookSecret(config);\nconst server = createShiphookServer(config);\nawait server.start();\n```\n\n---\n\n## License\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcap-jmk-real%2Fshiphook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcap-jmk-real%2Fshiphook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcap-jmk-real%2Fshiphook/lists"}