fix(deploy): give migrate the API's client-address settings, and say what Doctor checked
Cause of the production report. Doctor said "Direct client-address mode" while the running api had EKKLESIA_CLIENT_ADDRESS_MODE=trusted-proxy.
Doctor checks the client-address configuration of the process it runs in.
Operators run it as migrate.
compose.proxy.yaml gave the three trusted-proxy variables to api only.
Doctor therefore validated an empty configuration and reported direct mode for an installation that trusts its proxy.
Commits
Failing tests first. On main:
tests/deploy.test.ts: migrate gets no client-address environment;
core/tests/doctor.test.ts: the check does not say whose configuration it read;
scripts/smoke-deploy.sh: Doctor through the proxy overlay must report Trusted-proxy client-address mode. Not run against main (Docker); it follows from the static test.
The fix.
Change
Why
compose.proxy.yaml: the variables are defined once as a YAML anchor and applied to apiandmigrate
Doctor checks what the API runs. Rendered with docker compose config: api is byte-for-byte unchanged, and migrate matches it, keeping NODE_EXTRA_CA_CERTS from the base
The README's plain docker compose run --rm migrate … read compose.yaml alone, so even with the overlay fixed Doctor would not have seen it. This is what the instance's deploy/.env already does
Doctor's client-address check, every outcome, gets one more detail line
It says it checked the environment Doctor runs with, and how to read the running API's own value: docker compose exec api printenv EKKLESIA_CLIENT_ADDRESS_MODE (confirmed to work in the image)
deploy/README.md
Run operator commands with the same Compose files as the stack, and why it matters for Doctor
Verification
pnpm verify: passes.
bash scripts/smoke-deploy.sh (same-origin, Docker): passes, including ok Doctor: READY, verify-full with the private CA, storage reachable, the API's client-address mode, no secret printed.
The five Biome warnings in tests/deploy.test.ts (noTemplateCurlyInString on Compose ${…} strings) are pre-existing and unchanged.
For the instance
The instance vendors deploy/ verbatim, and its deploy/.env already sets COMPOSE_FILE with the proxy overlay. After the platform pin bump and scripts/vendor-deploy.sh, its documented Doctor command reports trusted-proxy mode with no other change.
## fix(deploy): give `migrate` the API's client-address settings, and say what Doctor checked
**Cause of the production report.** Doctor said "Direct client-address mode" while the running `api` had `EKKLESIA_CLIENT_ADDRESS_MODE=trusted-proxy`.
- Doctor checks the client-address configuration of **the process it runs in**.
- Operators run it as `migrate`.
- `compose.proxy.yaml` gave the three trusted-proxy variables to `api` only.
Doctor therefore validated an empty configuration and reported direct mode for an installation that trusts its proxy.
### Commits
1. **Failing tests first.** On `main`:
- `tests/deploy.test.ts`: `migrate` gets no client-address environment;
- `core/tests/doctor.test.ts`: the check does not say whose configuration it read;
- `scripts/smoke-deploy.sh`: Doctor through the proxy overlay must report `Trusted-proxy client-address mode`. Not run against `main` (Docker); it follows from the static test.
2. **The fix.**
| Change | Why |
|---|---|
| `compose.proxy.yaml`: the variables are defined once as a YAML anchor and applied to `api` **and** `migrate` | Doctor checks what the API runs. Rendered with `docker compose config`: `api` is byte-for-byte unchanged, and `migrate` matches it, keeping `NODE_EXTRA_CA_CERTS` from the base |
| `env/compose.env.example`: `COMPOSE_FILE=compose.yaml:compose.proxy.yaml` | The README's plain `docker compose run --rm migrate …` read `compose.yaml` alone, so even with the overlay fixed Doctor would not have seen it. This is what the instance's `deploy/.env` already does |
| Doctor's client-address check, every outcome, gets one more detail line | It says it checked the environment Doctor runs with, and how to read the running API's own value: `docker compose exec api printenv EKKLESIA_CLIENT_ADDRESS_MODE` (confirmed to work in the image) |
| `deploy/README.md` | Run operator commands with the same Compose files as the stack, and why it matters for Doctor |
### Verification
- `pnpm verify`: passes.
- `bash scripts/smoke-deploy.sh` (same-origin, Docker): passes, including `ok Doctor: READY, verify-full with the private CA, storage reachable, the API's client-address mode, no secret printed`.
The five Biome warnings in `tests/deploy.test.ts` (`noTemplateCurlyInString` on Compose `${…}` strings) are pre-existing and unchanged.
### For the instance
The instance vendors `deploy/` verbatim, and its `deploy/.env` already sets `COMPOSE_FILE` with the proxy overlay. After the platform pin bump and `scripts/vendor-deploy.sh`, its documented Doctor command reports trusted-proxy mode with no other change.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Behind the reference proxy the API runs in trusted-proxy mode, but
compose.proxy.yaml gives those variables to `api` only. The documented
Doctor command runs as `migrate`, so it validated an empty
configuration and reported "Direct client-address mode" for an
installation that trusts its proxy. That is what the first production
installation saw.
Fails today:
- deploy.test.ts: the proxy overlay gives `migrate` no client-address
environment;
- doctor.test.ts: the check does not say whose configuration it read;
- smoke-deploy.sh: Doctor through the proxy overlay does not report
trusted-proxy mode (Docker).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Doctor checks the client-address configuration of the process it runs
in, and operators run it as `migrate`. The proxy overlay set
trusted-proxy mode on `api` only, so Doctor reported "Direct
client-address mode" for an installation that trusts its proxy.
- compose.proxy.yaml defines the three variables once, as a YAML
anchor, and applies it to both `api` and `migrate`. Rendered with
`docker compose config`, `api` is unchanged and `migrate` now
matches it, keeping NODE_EXTRA_CA_CERTS from the base.
- The example deploy/.env sets
COMPOSE_FILE=compose.yaml:compose.proxy.yaml, as the instance already
does. Plain `docker compose run --rm migrate ...` in the README then
runs with the overlay; it used to read compose.yaml alone.
- Every client-address check in Doctor now says it checked the
environment Doctor runs with, and how to read the running API's own
value (`docker compose exec api printenv
EKKLESIA_CLIENT_ADDRESS_MODE`, confirmed to work in the image).
- The deploy README explains why operator commands need the same files
as the stack.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
fix(deploy): give
migratethe API's client-address settings, and say what Doctor checkedCause of the production report. Doctor said "Direct client-address mode" while the running
apihadEKKLESIA_CLIENT_ADDRESS_MODE=trusted-proxy.migrate.compose.proxy.yamlgave the three trusted-proxy variables toapionly.Doctor therefore validated an empty configuration and reported direct mode for an installation that trusts its proxy.
Commits
main:tests/deploy.test.ts:migrategets no client-address environment;core/tests/doctor.test.ts: the check does not say whose configuration it read;scripts/smoke-deploy.sh: Doctor through the proxy overlay must reportTrusted-proxy client-address mode. Not run againstmain(Docker); it follows from the static test.compose.proxy.yaml: the variables are defined once as a YAML anchor and applied toapiandmigratedocker compose config:apiis byte-for-byte unchanged, andmigratematches it, keepingNODE_EXTRA_CA_CERTSfrom the baseenv/compose.env.example:COMPOSE_FILE=compose.yaml:compose.proxy.yamldocker compose run --rm migrate …readcompose.yamlalone, so even with the overlay fixed Doctor would not have seen it. This is what the instance'sdeploy/.envalready doesdocker compose exec api printenv EKKLESIA_CLIENT_ADDRESS_MODE(confirmed to work in the image)deploy/README.mdVerification
pnpm verify: passes.bash scripts/smoke-deploy.sh(same-origin, Docker): passes, includingok Doctor: READY, verify-full with the private CA, storage reachable, the API's client-address mode, no secret printed.The five Biome warnings in
tests/deploy.test.ts(noTemplateCurlyInStringon Compose${…}strings) are pre-existing and unchanged.For the instance
The instance vendors
deploy/verbatim, and itsdeploy/.envalready setsCOMPOSE_FILEwith the proxy overlay. After the platform pin bump andscripts/vendor-deploy.sh, its documented Doctor command reports trusted-proxy mode with no other change.🤖 Generated with Claude Code
4a9012f64ctof1d6501239