Skip to content

ci: Docker image on ghcr.io - #148

Merged
Madraka merged 3 commits into
mainfrom
ci/docker-image
Nov 7, 2026
Merged

Madraka merged 3 commits into
mainfrom
ci/docker-image

Conversation

@Madraka

@Madraka Madraka commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

What

Steps 2–4 of #143: the official self-host image, its compose file, the release workflow and the guide. Opened against feat/selfhost-runtime (#147) because the image's entrypoint needs that PR's --init-if-empty, CLOUDHAL_HOST and CLOUDHAL_BASE_URL; GitHub retargets it to main when #147 merges.

  • deploy/docker/Dockerfile: multi-stage on node:24-bookworm-slim. The build stage (install.mjs) installs @cloudhal/cli + create-cloudhal with plain npm, from the registry (CLOUDHAL_VERSION) or from packed tarballs (tarballs/index.json, edge), then the blog starter's runtime dependencies next to them so cloudhal build works on the volume without an install or network. Runtime: tini, ca-certificates, the node user, /data volume, EXPOSE 8787, CLOUDHAL_HOST=0.0.0.0, CLOUDHAL_INIT=blog, a HEALTHCHECK on the existing public /api/health (node fetch, no curl), ENTRYPOINT → cloudhal studio --init-if-empty in /data; OCI labels. No compiler: better-sqlite3 13 ships its prebuilds inside the npm package (prebuilds/linux-x64, linux-arm64, musl too), verified on an amd64 build.
  • bin/site-build: the public site as static HTML into /data/dist, linking the image's node_modules into the project on first use (option (a) of the issue). No publish hook: the clean one (SiteGraphStore.onPublished + the release purger + a child-process build) is a feature of its own, left as a follow-up issue (text in the session notes; gh issue create was refused by the permission classifier) and documented as docker compose exec cloudhal site-build / a cron line.
  • compose.yml, .env.example, Caddyfile: service cloudhal on volume cloudhal-data, bound to 127.0.0.1 by default; profile caddy with automatic TLS for CLOUDHAL_BASE_URL (Studio, proxied with X-Forwarded-*) and CLOUDHAL_SITE_URL (the built site, read-only mount).
  • .github/workflows/docker.yml: workflow_call (from release.yml, next to template), workflow_dispatch (a version, or edge), nightly edge from scripts/pack-packages.ts, and a pull_request trigger on the image's files that builds amd64 without pushing. Tags X.Y.Z, X.Y, latest (release only; a dispatch never moves it), edge (nightly only), sha-…; linux/amd64,linux/arm64, cache type=gha, sbom, provenance: mode=max, actions/attest-build-provenance; then scripts/docker-smoke.ts (empty volume → healthy → first owner through the API → publish → site-build → the built home page) and Trivy (CRITICAL, fixed only). Every action pinned to a SHA. Dependabot gets docker and docker-compose for deploy/docker.
  • Docs: docs/guides/self-host.md (requirements, quick start, public origin and proxies, env table, the public site, upgrades with "pin X.Y", backup/restore, health, limits), the README paragraph, CONTRIBUTING "Releasing" step 5, deploy/docker/README.md, the docs site's index.

Verified locally (Apple Silicon, Docker Desktop)

docker build --platform linux/amd64 --build-arg CLOUDHAL_VERSION=0.6.2 -t cloudhal:test deploy/docker   # ok; sqlite 3.53.4 loads, uid 1000, tini
node scripts/pack-packages.ts deploy/docker/tarballs && docker build -t cloudhal:local deploy/docker       # edge, arm64 native
node scripts/docker-smoke.ts --image cloudhal:local                                                        # passed
CLOUDHAL_TAG=local docker compose -p cloudhal-smoke --env-file .env.example up -d                         # healthy; curl /api/health → {"ok":true}

Then in the browser: sign-up of the first owner, the scaffolded site listed, Publish from the site page, docker compose exec cloudhal site-build → /data/dist/index.html shows the site name; down -v. The 0.6.2 image installs and runs the CLI but cannot start as a container until a release carries #147 (no --init-if-empty, no CLOUDHAL_HOST), so the first publish to ghcr should be the next release, not a backfill of 0.6.2.

Checklist

  • pnpm lint, pnpm size:check, apps/docs repo-docs test pass locally (full pnpm check in CI); the image's own CI is this workflow's pull_request run
  • Contract change? — n/a
  • User-visible change in a published package? — none (CI, deploy files and docs only)
  • Commits are signed off (git commit -s, DCO)
  • Docs / AGENTS.md updated if behaviour or commands changed

🤖 Generated with Claude Code

Madraka and others added 2 commits November 8, 2026 01:40
deploy/docker: a multi-stage Dockerfile on node:24-bookworm-slim that
installs @cloudhal/cli and create-cloudhal from npm (CLOUDHAL_VERSION) or
from packed tarballs (edge) with the blog starter's dependencies next to
them, non-root, tini, a /data volume, port 8787, a HEALTHCHECK on
/api/health and an entrypoint running `cloudhal studio --init-if-empty`;
`site-build` writes the public site to /data/dist; compose.yml with an
optional Caddy profile (automatic TLS, Studio proxied, the built site
served), .env.example and a Caddyfile.

.github/workflows/docker.yml: called by release.yml after the npm publish,
by workflow_dispatch (a version, or edge) and nightly (edge from the
repository's own tarballs, scripts/pack-packages.ts); linux/amd64 +
linux/arm64, SBOM, provenance, a build attestation, the smoke test of
scripts/docker-smoke.ts and a Trivy gate; a pull request that touches the
image builds and tests it without pushing. Dependabot watches the base
image and the compose file.

docs/guides/self-host.md, README, CONTRIBUTING "Releasing" step 5.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com>
Base automatically changed from feat/selfhost-runtime to main November 7, 2026 22:42
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant