#21: make the stack deployable, and document how
Three things stood between this and a real deployment. A missing JWT_SECRET fell back to a constant that is published in this repository, so any deployment that forgot the variable would have accepted session tokens anyone could mint, including an admin one. The auth service now refuses to start without a secret of at least 32 characters. The test suites set it through vitest config, because ESM hoists imports and an assignment inside a test file runs too late. Session cookies were issued without the Secure attribute: it is driven by NODE_ENV, which compose never set. Behind a TLS terminator that is a downgrade waiting to happen. Nothing created the first mailbox. A fresh install has no domain and no account, and every route into the console needs one - so there was no first login. There is now a create-admin command, which also provisions the standard folders and the four system aliases. It is a deliberate command rather than a bootstrap on boot: creating an administrator as a side effect of starting a container is how a deleted account quietly comes back. Also: the production images were shipping compiled test files, since the build compiled everything under src. A separate build config excludes them while lint still type-checks them. Documentation. README.md covers what this is, how it is put together, and what is not finished - stated plainly, because a mail server that half works loses mail. docs/DEPLOYMENT.md is the Coolify path in the order it has to happen, starting with the three prerequisites no code can satisfy: outbound port 25, the PTR record, and the DNSSEC delegation. docs/OPERATIONS.md is the runbook - health states, certificates, backups, reading a delivery failure, DKIM rotation, and an explicit list of what is not automated. .env.production.example replaces guessing which of the dev defaults are safe: none of them are. docs/ was gitignored as a place for internal notes; only docs/internal/ is now, so these guides ship with the code. Every command the documentation tells an operator to run was executed against a running stack: create-admin, preflight, the health endpoint, the published mail ports, and the Secure cookie. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
30014f0f41
commit
c0387f6961
9 files changed
+641
-4
No files matched your search
@@ -1,4 +1,4 @@
|
||||
.PHONY: up down logs test lint migrate-up migrate-down gen-dev-cert seed
|
||||
.PHONY: up down logs test lint migrate-up migrate-down gen-dev-cert seed preflight create-admin reset-password
|
||||
|
||||
up:
|
||||
docker compose --env-file .env up --build
|
||||
@@ -35,3 +35,23 @@ gen-dev-cert:
|
||||
|
||||
seed:
|
||||
docker compose exec -T db psql -U $${POSTGRES_USER:-lambdamail} -d $${POSTGRES_DB:-lambdamail} < scripts/dev-seed.sql
|
||||
|
||||
# Environment diagnostics (PLAN.md section 15). Run this before pointing DNS at
|
||||
# the host: it reports outbound port 25, PTR/FCrDNS, RBL listings and the
|
||||
# Cloudflare token scope.
|
||||
preflight:
|
||||
docker compose run --rm --entrypoint /app/lambdamail-protocols protocols preflight
|
||||
|
||||
# First login on a fresh deployment. Nothing else creates a mailbox, so without
|
||||
# this there is no way into the admin console.
|
||||
# make create-admin EMAIL=you@example.com PASSWORD='...'
|
||||
create-admin:
|
||||
@test -n "$(EMAIL)" || (echo "EMAIL is required" && exit 1)
|
||||
@test -n "$(PASSWORD)" || (echo "PASSWORD is required" && exit 1)
|
||||
docker compose run --rm --entrypoint node auth dist/cli.js create-admin "$(EMAIL)" "$(PASSWORD)"
|
||||
|
||||
# Recovers a locked-out account. Every session it had is signed out.
|
||||
reset-password:
|
||||
@test -n "$(EMAIL)" || (echo "EMAIL is required" && exit 1)
|
||||
@test -n "$(PASSWORD)" || (echo "PASSWORD is required" && exit 1)
|
||||
docker compose run --rm --entrypoint node auth dist/cli.js reset-password "$(EMAIL)" "$(PASSWORD)"
|
||||
Reference in new issue
Block a user