docs(operations): env-vars runbook + gitignore .env.production.snapshot*#34
Merged
Conversation
Documents the manual VPS env-injection procedure as it stands today, plus the GitHub-Actions-managed PROD_ENV_FILE path to retire it when the next change comes up. Why now: today's SMTP env injection (issue #27) exposed two procedural gaps that bit us live: 1. `docker compose restart` does NOT reload env_file — it re-reads only the compose definition. The env_file is loaded at container CREATION, not restart. You MUST `up -d --force-recreate` to pick up env edits. We hit this on the SMTP rollout: env was injected, restart ran clean, but the container kept logging "SMTP not configured" because it was still running with its boot-time env. Switched to force-recreate and the SMTP_HOST appeared. 2. The local .env.production.snapshot files weren't gitignored. They contain real production credentials. Caught before any commit, but the gitignore patches both `.env.production.snapshot` (latest) and `.env.production.snapshot.*` (per-change archival copies). Existing .gitignore covered `.env` / `.env.local` / `.env.production` / `.env.*.local` but NOT `.env.production.snapshot` (different shape). docs/operations/env-vars.md covers: - Where env vars live across 5 locations (VPS .env, local .env, two snapshot files, .env.example) and which is authoritative - The restart-vs-recreate gotcha (load-bearing) - Step-by-step procedures: add/change env, rotate secret, emergency rollback (from .env.bak.<ts> backups), full re-creation from local snapshot - Service-specific operational pre-reqs: Brevo IP allowlist (104.207.143.14 required, 5.7.1 errors otherwise), SPF/DKIM/DMARC DNS records on zeroauth.dev for inbox delivery, Postgres password rotation order, DIDRegistry transferOwnership order on blockchain wallet rotation - The plan to retire manual editing: GitHub Actions secret PROD_ENV_FILE written to /opt/zeroauth/.env on every deploy. Backwards- compatible — guarded by `if: env.PROD_ENV_FILE != ''` so today's manual flow keeps working until the secret is added in the GH UI. - An audit-log table at the bottom — every production env change adds a row (date, who, keys touched, rationale). First entry: today's SMTP injection. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pulkitpareek18
added a commit
that referenced
this pull request
May 15, 2026
…ot* (#34) Documents the manual VPS env-injection procedure as it stands today, plus the GitHub-Actions-managed PROD_ENV_FILE path to retire it when the next change comes up. Why now: today's SMTP env injection (issue #27) exposed two procedural gaps that bit us live: 1. `docker compose restart` does NOT reload env_file — it re-reads only the compose definition. The env_file is loaded at container CREATION, not restart. You MUST `up -d --force-recreate` to pick up env edits. We hit this on the SMTP rollout: env was injected, restart ran clean, but the container kept logging "SMTP not configured" because it was still running with its boot-time env. Switched to force-recreate and the SMTP_HOST appeared. 2. The local .env.production.snapshot files weren't gitignored. They contain real production credentials. Caught before any commit, but the gitignore patches both `.env.production.snapshot` (latest) and `.env.production.snapshot.*` (per-change archival copies). Existing .gitignore covered `.env` / `.env.local` / `.env.production` / `.env.*.local` but NOT `.env.production.snapshot` (different shape). docs/operations/env-vars.md covers: - Where env vars live across 5 locations (VPS .env, local .env, two snapshot files, .env.example) and which is authoritative - The restart-vs-recreate gotcha (load-bearing) - Step-by-step procedures: add/change env, rotate secret, emergency rollback (from .env.bak.<ts> backups), full re-creation from local snapshot - Service-specific operational pre-reqs: Brevo IP allowlist (104.207.143.14 required, 5.7.1 errors otherwise), SPF/DKIM/DMARC DNS records on zeroauth.dev for inbox delivery, Postgres password rotation order, DIDRegistry transferOwnership order on blockchain wallet rotation - The plan to retire manual editing: GitHub Actions secret PROD_ENV_FILE written to /opt/zeroauth/.env on every deploy. Backwards- compatible — guarded by `if: env.PROD_ENV_FILE != ''` so today's manual flow keeps working until the secret is added in the GH UI. - An audit-log table at the bottom — every production env change adds a row (date, who, keys touched, rationale). First entry: today's SMTP injection.
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.
Documents the manual VPS env-injection procedure (as it stands today after the SMTP rollout) plus the GitHub-Actions-managed PROD_ENV_FILE path that retires it on the next change.
Why now
Today's SMTP env injection for issue #27 exposed two real procedural gaps:
What's in the runbook
`docs/operations/env-vars.md`:
Test plan
🤖 Generated with Claude Code