Welcome
A self-hosted PaaS that deploys GitHub repos as Podman containers, driven from a browser dashboard backed by a fleet of worker nodes.
WiseHosting is a small PaaS that lets users deploy GitHub (or GitLab / Bitbucket / Codeberg) repos as Podman containers — driven from a browser dashboard, a Go control plane, and a fleet of self-hosted worker nodes.
New here? Two-minute briefing
- PaaS = "platform as a service". Users push code, the platform builds and runs it for them.
- Control plane = the single Go binary that runs the dashboard, REST API, and the WSS hub.
- Worker = a separate Linux host that actually runs user containers via Podman.
- WSS = WebSocket Secure — the persistent channel CP and workers use to swap jobs and stats.
Anything else look like alphabet soup? The Glossary defines every acronym.
Get started fast
Spin up the control plane locally with Postgres, then add a worker host.
Understand the system
See how the control plane, scheduler, workers, and dashboard fit together.
Networking deep-dive
The WireGuard mesh that carries every byte of CP↔worker control traffic.
Deploy to production
Provision worker nodes, configure Cloudflare Tunnels, cut releases.
Read the code map
Per-package, per-function reference for every Go file in the repo.
Tour the dashboard
React 19 / Vite 8 SPA — routing, pages, components, polling.
What's in the box
| Component | Path | Role |
|---|---|---|
| Control plane | ./main.go | REST API, scheduler, alert manager, embedded dashboard — single Go binary |
| Worker agent | ./cmd/worker-agent | Connects out via WSS, runs Podman containers for end users |
| Dashboard | internal/web/spa | React SPA (login, projects, deployments, alerts, usage), served by the control plane |
| PostgreSQL | — | System of record. Schema applied via golang-migrate from internal/database/migrations/ |
Auth boundaries
- User → Dashboard — sign-in is Google OAuth only, with optional per-user TOTP 2FA in front of the session-cookie issue. The control plane sets a 30-day
wh_sessionHttpOnly cookie backed by a row insessions; every login/logout/revoke and every privileged dashboard action (deploy, restart, env-var write, domain verify, …) is appended toaudit_events. - Worker → API — connections ride a self-hosted WireGuard mesh (
10.50.0.0/24). The worker registers once withapi_server.secret+ its rawapi_key, then receives a 15-minute HS256 JWT it refreshes 2 minutes before expiry through/v1/workers/refresh-token. The control plane stores onlysha256(api_key)(columnapi_key_hash); the per-envelope HMAC key issha256(rawKey)derived independently on both sides — the raw key never crosses the wire after registration. - Git providers (GitHub / GitLab / Bitbucket / Codeberg) — linked after sign-in via OAuth; tokens stored AES-GCM-encrypted with HKDF-derived per-purpose keys. They cannot be used to sign in.
Where to next
- New here? Start with Getting started.
- Wiring an extra worker? Jump to Worker deployment.
- Reading the source? Open the Code map.