Files
Lyu e81f904afd fix(deploy): run the self-hosted stack from the checkout, and from its root
Self-hosting ran ghcr.io/insforge/postgres-all, which bakes its configuration
in. The published image's postgresql.conf dates from May and its
shared_preload_libraries omits insforge_pg_utils — the hook that lets
project_admin create policies on tables it does not own — so RLS on managed
tables fails on every self-hosted install, while this repo's own config has
carried the hook, its grant-role GUCs and insforge.internal_schemas for
months. Baked configuration cannot track a moving schema. The compose file now
runs the base image and mounts the three files from the checkout.

Same split, same result, for edge functions: ghcr.io/insforge/deno-runtime is
built in InsForge/deploy-provider, and hashing every historical revision of
functions/server.ts and functions/worker-template.js against the image's
copies matches none of them. It is 92 lines behind on server.ts and 175 on
worker-template.js, and where this repo registers self.onmessage before the
top-level await (d12e69c3b, "fix 504 race") the image still assigns it inline.
The stack now runs the official denoland/deno image with functions/ mounted
from the checkout, read-only and with --no-lock, since Deno otherwise tries to
write deno.lock back into it and the container restart-loops.

With a checkout part of self-hosting rather than an optional convenience:

- deploy/setup.sh sparse-checks out the ten files the stack reads (~700KB over
  the network, no build step) and generates JWT_SECRET, ENCRYPTION_KEY,
  ROOT_ADMIN_PASSWORD and POSTGRES_PASSWORD at mode 600. Postgres reads that
  last one only at cluster init, so it has to be settled before first boot;
  it defaulted to "postgres" and was left to a manual checklist item.
  Re-running the script after `git merge` is what picks up files a release
  adds — a merge lands them in git but not in a sparse working tree. It
  refuses to touch a full development clone, where the sparse-checkout would
  empty the working tree.
- One .env.example, at the repo root. The copy under deploy/docker-compose/
  had drifted: the S3 storage settings went undocumented there for months.
- .env sits beside it, and COMPOSE_FILE inside it points Compose at
  deploy/docker-compose/docker-compose.yml, so every command runs from the
  checkout root. Compose reads .env, and COMPOSE_FILE within it, from the
  directory you are in, while the compose file's relative mounts still resolve
  against its own directory. The template ships the development value, which
  resolves byte-identically to today's auto-discovery; setup.sh rewrites the
  line. Shipping the production value there would have silently repointed
  every developer's `docker compose up` at published images.
- Installs predating this layout keep .env beside the compose file, where
  Compose ignores it — secrets that no longer reach Postgres read as a lost
  database. setup.sh moves it. Those installs have no COMPOSE_PROJECT_NAME,
  and Compose derives "docker-compose" for them from the compose file's
  directory, the same name they already run under, so their volumes stay
  attached.

PGDATA is pinned to the subdirectory postgres-all baked into its own ENV.
Changing it makes Postgres initdb an empty cluster beside the real one, which
reads as total data loss.

Dockerfile.deno did not build: the base image already ships a deno user at uid
1000, so `addgroup -S deno` exits 1. Nothing caught it because the override
only added `build:` to services that already declared `image:`, and Compose
skips building when the image is present — inert for anyone who had pulled it,
broken for anyone who had not.

postgrest's healthcheck is gone, and insforge depends on it with
service_started. On amd64 that image is 24 entries — bin/postgrest and a
certificate directory, no shell — so a CMD-SHELL probe reports unhealthy
forever and `docker compose up -d` ends with "dependency failed to start:
container postgrest-1 is unhealthy". The backend never starts. The same probe
and condition are on main; it went unnoticed because the arm64 image for that
tag is a full Debian build with a shell, so the stack comes up on an Apple
Silicon laptop and fails on the Linux servers people self-host on.

Verified on an amd64 EC2 instance following the guide as written: stack up,
/api/health 200 at 2.2.9, 63 migrations, insforge_pg_utils preloaded, CREATE
POLICY on storage.objects as project_admin, and an edge function created
through the API and invoked end to end.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 10:53:49 -07:00

17 lines
697 B
Docker

# The Deno function host, from this repository rather than a published image.
# ghcr.io/insforge/deno-runtime is built in another repo and its copy of
# functions/ matches no commit here, so fixes made here never reach it.
FROM denoland/deno:alpine-2.0.6
WORKDIR /app
# The base image already ships a deno user at uid 1000 — creating it again fails
# the build, which is how this file sat broken while nothing rebuilt it.
COPY --chown=deno:deno functions /app/functions
# A fresh named volume inherits the mount point's ownership from the image, so
# this is what lets the non-root user populate the module cache on first start.
RUN mkdir -p /deno-dir && chown deno:deno /deno-dir
USER deno