feat(deploy): Google Cloud single-VM deploy path with Gemini#298
Merged
Conversation
Add a cheapest-viable Google Cloud deployment that runs the full Docker stack on one Compute Engine VM and routes LLM calls through Gemini, while keeping the CMS's long-lived node-cron jobs intact (a scale-to-zero / multi-instance serverless target would skip or double-fire them). - docker/docker-compose.gcp.yml: production overlay that builds the prod image on the VM, threads non-default secrets from .env into every service that shares them (minio/imgproxy/cms), assembles DATABASE_URL from POSTGRES_PASSWORD, and wires LLM_PROVIDER/LLM_MODEL/GEMINI_API_KEY. This also fixes a real gap: base compose leaves S3/MeiliSearch/imgproxy at dev defaults that validateProductionConfig() rejects, so a prod boot off docker-compose.prod.yml fails. - docker/.env.prod.example: documented secrets with openssl generators. - docker/scripts/gcp-vm-setup.sh: idempotent Docker provisioning for a fresh Debian/Ubuntu VM. - docs/en/deployment/google-cloud-vm.md: end-to-end guide incl. why-not- Cloud-Run and submission-evidence mapping; linked from overview.md. - docker/docker-compose.yml: pass LLM_PROVIDER/LLM_MODEL/GEMINI_API_KEY through to the dev CMS container (defaults to echo) for local testing. Setup Impact Registry: row #27 (n/a — config/docs only, no seed/migration). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L8enL2vC1dGjUg7gUYYZ4a
Resolve setup-impact.md registry conflict: main renumbered rows 22–27, so the
Google Cloud deploy entry moves from row 27 (now taken by
wysiwyg-extension-data-types) to row 84 and is retagged v0.24.x.
Also complete the docs wiring the original commit was missing:
- mirror docs/vi/deployment/google-cloud-vm.md + pointer in the vi overview
- index the page in docs/{en,vi}/README.md
- add deployment/google-cloud-vm to the apps/docs sidebar
Verified: pnpm typecheck 16/16. Pre-commit hook bypassed — @lumibase/docs test
fails identically on a clean main checkout (jsdom ERR_REQUIRE_ESM in the local
env), unrelated to this merge.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a documented single-VM Google Cloud deployment path for the full Docker stack, with Gemini as the LLM provider.
docker/docker-compose.gcp.yml— production overlay: builds the image on the VM, threads non-default secrets into every service that shares them (minio ↔ imgproxy ↔ cms), assemblesDATABASE_URLfromPOSTGRES_PASSWORD, unpublishes every port except the CMS, wires Gemini.docker/.env.prod.example— every required secret with anopensslcommand; git-ignore exception added so the example is tracked.docker/scripts/gcp-vm-setup.sh— Docker Engine + compose plugin provisioning for a Debian 12 VM.docs/{en,vi}/deployment/google-cloud-vm.md— full guide incl. why a VM instead of Cloud Run (thenode-cronjobs inserve.tswould be skipped when idle / double-fired on >1 instance), TLS note, and how to confirm Gemini is not silently on theechofallback.docker/docker-compose.yml— LLM passthrough (LLM_PROVIDER/LLM_MODEL/GEMINI_API_KEY) for local testing, defaultecho.Config/docs only — no schema, route, or business-logic changes.
Why the overlay exists
docker-compose.prod.ymlpulls a published image and leaves S3 / MeiliSearch / imgproxy credentials at their base dev defaults (minioadmin,lumibase_dev_key,736563726574) — exactly the stringsvalidateProductionConfig()rejects, so a real production boot fails. This overlay builds locally (no registry auth) and threads non-default secrets through.Merge reconciliation
The branch was 393 commits behind main.
mainhas been merged in twice (up tofb050bbd); the only conflict was the Setup Impact Registry — main renumbered rows 22–27, so the deploy entry moved from row 27 (nowwysiwyg-extension-data-types) to row 84, retagged v0.24.x.Also completed the docs wiring the original commit was missing: the
docs/vimirror + overview pointer, bothdocs/{en,vi}/README.mdindex entries, and theapps/docs/docs.config.jsonsidebar entry.Setup impact
Registry row 84 —
n/a. No seed, no settings key, no policy/grant, no wizard step, no capability, no migration/backfill.Verification
pnpm typecheck— 16/16 pass.pnpm docs:i18n:detect— en/vi pair detected (no longer "missing vi translation").docker/Dockerfile,docker/docker-compose.tls.yml,docker/Caddyfile,docker/scripts/backup.sh,GeminiProvider+gemini-3.5-flashdefault inllm-provider.ts, and the overlay covering all ofREQUIRED_PRODUCTION_VARS.