FRAMEWORK
HostSSH as our Infrastructure Framework
The tech, and how the fleet's "deploy a new app" runbook becomes HostSSH automation. Companion to the DevOps
NEW-APP-DEPLOY.md(the manual runbook): that doc is the SPEC; this is the architecture that makes HostSSH own it.
What HostSSH is
A SaaS control plane + a single-binary agent that turns any VPS into managed infrastructure we (and customers) drive from one panel. 100% ours — Node + Go, zero PHP, no Coolify/Dokploy code (they're only migration sources + inspiration).
Three planes:
| Plane | Tech | Owns |
|---|---|---|
| Control plane (SaaS) | Next.js 16 · React 19 · Postgres (pgvector) | dashboard + /api/v1/*, fleet registry, deploy jobs queue, licensing/billing, white-label, tenants, audit, observability |
| Agent (the universal connector) | Go — one static ~7 MB binary, zero deps | build→run→route (HostPack→Docker→Traefik), capture/restore, hardening, host metrics, claims + runs deploy jobs |
| Data | pgvector Postgres · R2 · on-box secrets | per-app DBs, object storage, secret material (never leaves the box) |
The deploy model — pull-based jobs (the key decision, built + proven):
control plane enqueues → agent claims on its heartbeat → runs OUR pipeline
locally → streams state + logs back. No inbound connection to the box → works on
any provider, behind any NAT/firewall. Hardened: license-scoped, claimed_by-
fenced, 15-min reclaim lease, 30-min job timeout, jobs run off the heartbeat path.
"Connect to any VPS" + SaaS
- Connect:
curl … | shinstalls the signed agent → activates (ed25519 token verified) → heartbeats in → claims jobs. Any box joins the fleet in minutes. - SaaS: the control plane is already multi-tenant (tenants, white-label,
license codes, billing). Customer signs up → gets a license → installs the
agent on their VPS → manages everything from the panel. Revenue = license codes
- managed hosting + resold VPS margin.
The new-app deploy process → HostSSH automation mapping
Every phase of the manual fleet runbook maps to a HostSSH capability. Status is in OUR codebase today:
| # | Runbook phase | HostSSH capability | Status |
|---|---|---|---|
| 1 | Source (git repo) | deploy job + git-clone + Dockerfile autodetect | ✅ have |
| 2 | Database (per-app) | agent db create (postgres/mariadb/redis) | ✅ have |
| 3 | App | deployment + deploy job (jobs loop) | ✅ have (proven e2e) |
| 4 | Env / secrets | agent secrets + deployment_env (on-box custody) | ✅ have |
| 5 | Redis/Valkey | service template + prebuilt-image deploy | ✅ have |
| 6 | R2 / storage | BYO connector (connections) | 🟡 per-app wiring |
| 7 | Deploy + migrate | deploy job + release-phase migrate (RunOnce) | ✅ have |
| 8 | DNS + TLS | Traefik + ACME + Cloudflare DNS connector | ✅ have (needs CLOUDFLARE_DNS_TOKEN) |
| 9 | Backups | capture/restore + restic→R2 + drills | ✅ have |
| 10 | Image hygiene | keep-last-N image reaper + daily auto-run | ✅ have |
| 11 | Verify | healthcheck-gated deploy (liveness) | ✅ have |
The runbook is owned end to end as of 2026-06-23: source (git/Dockerfile) → build (HostPack/Dockerfile) → migrate → run → route → liveness-verify → DNS+TLS, with keep-last-N image hygiene. Remaining polish: per-app R2 storage wiring (#6), and a panel UI for the migrate/branch/DNS fields (the agent + actions already support them). Live use needs the owner-run steps (toolchain install, prod redeploy, the CLOUDFLARE_DNS_TOKEN).
Why this stack (the decisions)
- Go agent, zero deps → a single static binary customers run with no runtime to install; the lightest possible "connect to any VPS" footprint, and the prerequisite for clean image→image porting.
- Pull-based jobs → no inbound to the box; provider-agnostic; survives NAT.
- HostPack (Railpack/MIT) for builds; prebuilt-image path for run-only.
- Security spine first (PHASE 0): ed25519 license tokens, signed grace- refresh, TLS + cert pinning, signed reproducible binaries, hash-chained audit.
- Migration, not dependency:
migrate --from coolify|dokployimports a customer's existing platform onto our engine — the on-ramp to the SaaS.