feat(deployment): add Coolify Compose templates for Postgres and SQLite - #1
Merged
Merged
Conversation
Coolify could not run any of the existing Compose files. It treats one
file as the single source of truth, so the `-f compose.prod.yml -f
compose.sqlite.yml -f compose.tls.yml` layering has nowhere to go; it
runs its own Traefik, so the Caddy container and its `./Caddyfile` bind
mount are redundant; and `ports:` would publish Postgres on the host,
bypassing the proxy the platform exists to manage. Two standalone files
instead, one per database engine.
PUBLIC_ORIGIN is the reason these files are worth shipping rather than
leaving to each operator. `resolvePublicOrigins` auto-detects Render and
Railway and has no Coolify branch, and `server/auth/security.ts`
deliberately never trusts X-Forwarded-Proto. Coolify's Traefik terminates
TLS and forwards plain HTTP, so an unset PUBLIC_ORIGIN leaves the server
believing it is http:// and four things degrade — only one of them
loudly: the session cookie silently drops its Secure flag, the CSRF check
compares the wrong expected origin, real-time co-editing never connects
because the WebSocket upgrade runs that same origin guard, and MCP
connector URLs resolve local-only. Wiring `SERVICE_URL_INSTATIC_3001`
alongside `PUBLIC_ORIGIN=${SERVICE_URL_INSTATIC}` fixes all four and
follows a custom domain set later in the UI.
INSTATIC_SECRET_KEY is the other one that has to be right the first time.
The image runs NODE_ENV=production, where masterKey.ts throws at boot
unless the value decodes to exactly 32 bytes. Coolify's REALBASE64_32
emits base64 of 32 random bytes; the similarly-named BASE64_32 emits a
bare 32-character string that is not base64 at all and would fail
validation. Its own Plausible template uses REALBASE64_32 for an
identically-shaped key, so this is precedent rather than inference.
The SQLite template mounts /app/uploads and /app/data rather than the
single /app/storage root the Railway and Render templates use. That
layout exists because those platforms allow one disk, and it needs
RAILWAY_RUN_UID=0 to work at all: a volume mounted where the image has
no directory is created root-owned, and the non-root `bun` user cannot
write to it. The Dockerfile already creates and chowns both of these
paths before dropping privileges.
The gate in dockerConfig.test.ts covers the invariants that fail
silently rather than loudly — a stray `networks:` block (Coolify's
documented cause of intermittent HTTPS outages), a `ports:` mapping, a
missing PUBLIC_ORIGIN, the wrong base64 variable, or a drift back to
/app/storage. Comments carry the reasoning so the next reader knows why
the rule exists.
Verified against the published image rather than by inspection: both
stacks reach healthy, the Postgres stack applies 24 migrations into 38
tables, volumes come up bun-owned and writable, /health answers 200, and
no host port is published. Documented that the image is linux/amd64 only,
which is not incidental — pulling it on arm64 fails outright.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Lands the Coolify deployment target on our
mainso follow-up work can build on it while the upstream review runs.Same commit submitted upstream as CoreBunch#475.
Adds
docker-compose.coolify.yml(bundled Postgres) anddocker-compose.coolify.sqlite.yml(single container),docs/deployment/coolify.md, the Coolify rows indocs/deployment/README.md, release-bundle wiring, and acoolify docker configtest suite.Verification:
bun run buildclean,bun test6747 pass / 0 fail,bun run lintclean, anddocker compose configvalidates both Coolify files.🤖 Generated with Claude Code