Self-hosted one-command HTML deployment — Vercel-lite for your intranet.
Turn any HTML file, project folder or zip archive into a shareable URL on your own machine, NAS, VPS or intranet server.
pip install html-golive && golive initThat sets up everything and prints live URLs — open one and you're done. Then publish your own page:
golive publish report.html --name "Q3 Report" --slug q3
# → http://localhost:8787/q3Something not working? Run golive verify and paste the output into an issue.
- Why html-golive
- Quickstart
- Upgrading
- Features
- Architecture
- Configuration
- Data layer
- Security scanning
- Docker
- Roadmap
📖 Full user manual: docs/manual.md — every feature, organised by task (publishing, editor, access control, data, security, identity, migration, FAQ).
The built-in admin portal at /admin: sites, data, permissions,
stats, audit log, identity, data backend, security and settings —
dark/light themes, English and Chinese (toggle top-right).
- One command, one URL. No build step, no server code, no cloud
account.
golive publish→ share the link. - Everything becomes a single file. Folders and zips are bundled — CSS/JS inlined, images compressed and embedded (or uploaded through your own image host).
- Static pages, real data. Publish a plain HTML file that reads and
writes a real database via
window.TemplateAPI/window.SupabaseAPI— no backend code required. - Own your stack. Runs entirely on your infrastructure. No outbound calls at publish/serve time (details).
- Production habits built in. Slug collision checks, 10-snapshot rollback, credential/PII scanning on every publish, audit log.
pip install html-golive # core
pip install 'html-golive[oidc]' # + SSO / OpenID Connect login
pip install 'html-golive[image]' # + image compression (Pillow)
pip install 'html-golive[s3]' # + S3-compatible backends (boto3)
pip install 'html-golive[postgres]' # + self-hosted Postgres (psycopg3)golive publish index.html --name Demo --slug demo
golive publish ./my-project/ --slug app # folder → bundled single HTML
golive publish site.zip # zip / tar.gz work too
golive publish page.html --style apple # apply one of 19 CSS stylesgolive serve --port 8787 # foreground; Ctrl+C stops it
# → http://<your-host>:8787/demo
golive serve start # or run it in the background
golive serve status # pid, port, version
golive serve logs -f
golive serve stopgolive list # all published sites
golive publish new.html --update demo # overwrite update
golive rollback demo --dry-run # inspect snapshots, then --yes
golive preview draft.html # live preview + style panel
golive clone https://example.com --save-only # snapshot a public page
golive styles # list the 19 CSS styles
golive doctor # one-screen health check
golive serve status # is a server running? which version?
golive skill install # teach your AI agent to drive golive
# v0.3 — online editing & watermark
golive publish page.html --enable-editor --owner you@example.com
golive maintainer add demo teammate@example.com
golive publish page.html --watermark "CONFIDENTIAL"export GOLIVE_EDITOR_TOKEN=$(openssl rand -hex 16)
golive publish report.html --slug q3 --enable-editor --owner you@example.com
golive serve
# open http://localhost:8787/q3?editor_token=<token>&editor_user=you@example.com
# click ✏️ → edit text inline → 💾 save (snapshot taken automatically)Saves go through the same security scanner as publishes, are limited to
the site owner + maintainers, and every overwrite is preceded by a
rollback snapshot. With auth.provider: oidc the editor accepts the
login session instead of the token+header pair.
Enable OpenID Connect login — Google, Keycloak, Authentik, Auth0, or any IdP with a discovery document:
auth:
provider: oidc
oidc:
preset: google # or auth0 / okta / azure / keycloak / authentik
client_id: your-client-id
redirect_uri: https://pages.example.com/auth/callbackSet the client secret via GOLIVE_OIDC_CLIENT_SECRET and a stable
GOLIVE_COOKIE_SECRET in production. Since v0.8.0 every id_token is
signature-verified against the IdP's published keys (requires pip install 'html-golive[oidc]').
Login ≠ admin. Signing in proves who someone is; it does not grant management access. List superadmin emails separately:
admin: admins: [alice@corp.example]A common slip is putting
admins:at the top level — it has no effect there. See manual §16 for details.
pip install -U html-golive
golive serve restart # a running server keeps the OLD code until restarted
golive doctor # confirms CLI version == running service versionTwo things bite people:
- Updating the code does not update a running server. Restart it, then
let
golive doctorconfirm the two versions match. - Clones made before v0.7.0 cannot
git pull. That release force-pushedmainand rewrote history. Recovery commands are in the guide below (force pushes tomainare now blocked).
📖 docs/upgrading.md — PyPI / pipx / git paths, the v0.7.0 history-rewrite recovery (with and without local changes), the 0.6→0.7 SQLite data-layer default change, and how to roll back.
Publishing & content
- Single HTML / directory / zip / tar.gz publishing with asset bundling
- 19 built-in CSS beautification styles (
--style, custom font CDN viaGOLIVE_FONT_CDN_BASE) - Image compression (
--compress) and pluggable image upload (GOLIVE_UPLOADER_CMDcommand template, or native S3 uploader) - Website cloning (
golive clone <url>) with static snapshot mode
Operations
- Short slugs with reserved-word and collision checks
- Rollback with 10 snapshots per site
- Built-in static server with JSON API and health endpoint
- Live preview with hot reload and style-switch panel
golive doctorone-screen report: CLI vs running-service version, all three backends with paths and sizes, skill status, audit log- Background service management:
golive serve start|status|stop|restart|logs
Data & backends (v0.2, SQLite data layer in v0.7)
window.TemplateAPI/window.SupabaseAPIinjection — static pages get a real database with zero backend code- Three independent backend layers, each switchable on its own:
- storage (site HTML):
local(default) /s3/supabase - registry (site metadata):
sqlite(default) /postgres/supabase - data (TemplateAPI rows):
sqlite(default) /postgres/supabase/noneDefaults are fully local — SQLite files underGOLIVE_HOME, nothing to register. One Supabase project can back all three when you want them shared across machines.
- storage (site HTML):
golive migrate-check— port pages from other golive deployments- Docker Compose deployment (+ optional MinIO profile)
Editing, identity & watermarking (v0.3, signature-verified OIDC in v0.8)
- In-browser inline editor (
publish --enable-editor): contenteditable text editing with a save API that re-runs the full security pipeline, snapshots before every overwrite, and enforces owner/maintainer ACLs (golive maintainer add/remove/list) - Page watermarking (
--watermark [text]): canvas-tiled identity watermark — OIDC user, static text, or page meta tag; optional view-report webhook;GOLIVE_WATERMARK_OFF=1kill switch - Signature-verified OIDC login (v0.8.0):
auth.provider: oidcwith Google / Keycloak / Authentik / any discovery-document IdP; PKCE + signed session cookies; everyid_tokenchecked against IdP signing keys (iss/aud/exp/nonce,alg: nonerefused); presets for common providers; sessions accepted by the management and editor APIs - Optional LLM security review of weak scan hits via any
OpenAI-compatible endpoint (
security.llm.*), with a conservative degrade path and astrict_modegate
Admin portal (v0.5, config-store in v0.8)
- Web management portal at
/admin: site list/search, metadata editing, maintainer & ownership management, snapshot rollback, delete with slug confirmation — role-scoped (owner / maintainer / superadmin viaadmin.adminsorGOLIVE_ADMINS), plus superadmin stats dashboard and a JSONL audit trail (/api/admin/*JSON API for scripting) - 9-page admin console (v0.8.0): identity, data backends, security, global parameters — all configurable through the web UI with config-store: settings saved to the registry are live on next restart, no yaml editing required
AI agent skill (v0.7)
golive skill installdrops a ready-made AgentSkill into your agent's skills directory (auto-detected), teaching it to probe the environment before acting, publish and update by slug, wire upTemplateAPI, and never confuse this self-hosted CLI with a hosted deployment service- Ships inside the wheel, so installation works offline;
golive skill statusflags version drift
Safety
- Credential / PII scanning on every publish (YAML-extensible rules)
- Refusals identify the credential without reprinting it;
redact_mode: strictwithholds the host/database metadata too, for CI logs (v0.9) - Per-publish manifests +
golive doctor --siteto detect a page changed outside golive (v0.9) - Path-traversal-hardened server and archive extraction
- Token-protected management API (
GOLIVE_TOKEN)
┌────────────── golive core (pure logic) ───────────────────┐
│ bundle / image compress / CSS styles / clone / preview / │
│ security scanner / slug checker │
└──────┬──────────────────┬──────────────────┬──────────────┘
StorageBackend RegistryBackend DataBackend
site HTML/assets site metadata TemplateAPI/SupabaseAPI
│ │ │
local-fs / s3 / sqlite / postgres / sqlite (local file) /
supabase storage supabase postgres / supabase (PostgREST) / none
│
AuthProvider: none (default) / token (GOLIVE_TOKEN) / oidc (generic OIDC)
All data lives under GOLIVE_HOME (default ~/.golive/):
~/.golive/
├── sites/<site_id>/index.html published content
├── backups/<site_id>/ rollback snapshots (max 10)
├── registry.db SQLite registry + managed superadmins
├── data.db SQLite data layer (TemplateAPI rows)
├── audit.log admin action trail
├── logs/ operation log
└── cache/ style backups etc.
With the default backends the three SQLite/filesystem entries above are
the entire persistence story — no external service is involved. Pages
using TemplateAPI reach data.db through golive serve's
/api/data endpoint, so they must be loaded from the server rather than
opened as file://. See docs/data-layer.md.
Everything works with zero config. Two layers of knobs, env always wins over yaml:
Lookup order: --config <path> → $GOLIVE_CONFIG → ./golive.yaml →
$GOLIVE_HOME/golive.yaml. Full annotated example:
golive.example.yaml · backend combinations:
docs/backends.md
| Variable | Purpose |
|---|---|
GOLIVE_HOME |
data directory (default ~/.golive/) |
GOLIVE_TOKEN |
protect /api/sites (Bearer or X-Golive-Token) |
GOLIVE_EDITOR_TOKEN |
online-editor save token (falls back to GOLIVE_TOKEN) |
GOLIVE_WATERMARK_TEXT / GOLIVE_WATERMARK_OFF |
watermark text / global kill switch |
GOLIVE_OIDC_CLIENT_SECRET / GOLIVE_COOKIE_SECRET |
OIDC client secret / session-cookie HMAC key |
GOLIVE_LLM_BASE_URL / GOLIVE_LLM_MODEL / GOLIVE_LLM_API_KEY |
LLM security review endpoint |
GOLIVE_FONT_CDN_BASE |
swap fonts.googleapis.com for your font mirror |
GOLIVE_UPLOADER_CMD |
image-upload command template (mytool up {file}) |
GOLIVE_SUPABASE_URL / _ANON_KEY / _SERVICE_KEY |
Supabase backends |
GOLIVE_S3_AK / GOLIVE_S3_SK |
S3-compatible backends |
FIRECRAWL_API_KEY |
optional JS-heavy-page fallback for golive clone |
golive makes no outbound calls at publish/serve time. Exceptions:
golive clone <url> fetches the target page; golive preview downloads
a one-time Tailwind cache from cdn.tailwindcss.com on first run (fails
silently offline); injected styles reference public font CDNs
(override with GOLIVE_FONT_CDN_BASE); your own uploader command and
configured backends.
No server code to write. SQLite by default, so this works out of the box; point it at your own PostgreSQL or a Supabase project when you outgrow that:
golive publish app.html --data-model myapp_v1 # sqlite: nothing to set up
golive serveYour page then simply calls:
// namespaced record store
await TemplateAPI.upsert({ templateName: 'vote:alice', templateContent: {n: 1} });
const { total, list } = await TemplateAPI.listAll();
// or direct table access
const { rows } = await SupabaseAPI.query('feedback', { limit: 50 });Three backends, two shapes:
| Backend | Shape | Setup |
|---|---|---|
sqlite |
server-proxied | none — the default |
postgres |
server-proxied | pip install 'html-golive[postgres]' + GOLIVE_PG_DSN |
supabase |
page-direct | Supabase project + anon key |
Server-proxied backends keep the database connection on the server; the
page calls golive's /api/data and no credentials (no Postgres DSN) ever
reach the browser. Page-direct (Supabase) embeds the anon key in the
HTML, so RLS is mandatory there.
API signatures are stable contracts — pages built on any golive deployment run unchanged on yours. Full guide, including the RLS notes: docs/data-layer.md.
Note: if no data backend is configured,
--data-modelpublishes still succeed — the page gets a stub API that raises a clear "data backend not configured" error at call time (a warning is also printed at publish time).
Porting pages from another deployment?
golive migrate-check page.html reports anything deployment-specific
(migration guide).
Every publish is scanned against built-in rules — API keys, private
keys, database connection strings, PII patterns. Strong hits block the
publish; weak hits warn — and can optionally get a semantic second pass
from any OpenAI-compatible LLM (security.llm.base_url; works with
OpenAI / Azure / Ollama / self-hosted gateways). Unconfigured installs
keep pure rule verdicts; strict_mode: true refuses to publish without
AI review. Extend with your own YAML rules, or bypass a false positive
with --skip-scan. Details: docs/security.md
docker compose up -d golive # golive serve on :8787
docker compose --profile minio up -d # + local S3 stack for imagesM1 — core: publish/serve/rollback, styles, clone, preview, scan✅ v0.1M2 — data layer: Supabase backend trio, TemplateAPI/SupabaseAPI injection, S3 adapters, migrate-check, Docker Compose✅ v0.2M3 — editing & identity: inline editor with versioned save API, watermarking, OpenAI-compatible LLM security review, generic OIDC✅ v0.3M4 — docs & polish: OIDC provider presets, editor image upload, persistent cookie secret, full user manual✅ v0.4M5 — admin portal: web operations console at✅ v0.5/admin, role model (superadmin/owner/maintainer), ownership transfer, audit trailM6 — data management: data tab in the portal, audit log rotation✅ v0.6M7 — production identity & config: id_token signature verification for OIDC, trusted reverse-proxy auth, four admin pages (identity / data backend / security / settings), settings & scan rules in the database, English-by-default CLI, shareable LAN URLs✅ v0.7.5M8 — data portability & self-check:✅ v0.8golive export/import/migrateacross sqlite, postgres and supabase, andgolive verifyfor a real end-to-end test of the data path
Beyond v0.8 — the groundwork is complete, so what comes next is driven by what people actually run into. Candidates, roughly in order of likely demand: more storage channels (WebDAV), aggregation for very large tables, a shared session store (redis) for multi-instance setups, multi-user editing conflict UX, and group-based ACLs. If you hit a wall or want one of these sooner, open an issue — real use cases decide the order.
Issues and pull requests are welcome — see CONTRIBUTING.md for the development setup, code conventions and what a good bug report looks like. The whole test suite runs offline with no cloud account:
pip install -e '.[image,dev]'
python -m pytest tests/ -qMIT © 2026 Songhonglei
中文文档请见 README.zh-CN.md。
