Skip to content
prod 352bb92
Browse

5 · Wire .env templates

Objective — replace the vendor’s single .env with a three-environment template set (local / staging / production), preserving the original first, and generate a unique APP_KEY for local.

Steps at a glance:

  1. Back up the vendor env — Preserve the originals in the gitignored vault — your record of what the author expected.
  2. Lay down per-environment templates — Create one template per environment in the vault. Keep real secrets out of git — only .env.example is ever tracked.
  3. Activate local & generate the key — copy the local env into place and generate APP_KEY, so the app boots locally with secrets kept out of git.
  4. Per-environment values (reference) — The same keys take different values per environment. The ones that matter most:.
  5. Final verification — Run after all templates exist and local is active.

The vendor ships a .env (or .env.example). You’re about to replace it with one template per environment row in Zaj-PROJECT.md — but first preserve the original, because it often documents required keys you’d otherwise miss.

flowchart LR
V["vendor .env /<br/>.env.example"] -->|back up| Vault["project vault<br/>(gitignored)"]
Vault --> T["lay down<br/>.env.local / .staging / .production"]
T --> A["cp .env.local .env"]
A --> K["php artisan key:generate"]

Preserve the originals in the gitignored vault — your record of what the author expected.

  1. Copy the vendor env into the vault.

    Terminal window
    mkdir -p Admin-Local/1-Project/2-Vault
    [ -f .env ] && cp .env Admin-Local/1-Project/2-Vault/.env.vendor-original
    cp .env.example Admin-Local/1-Project/2-Vault/.env.vendor-example
    # Expected: vendor .env (if present) and .env.example copied into the vault
    • ✅ The vendor’s original env files are preserved in Admin-Local/1-Project/2-Vault/.

Create one template per environment in the vault. Keep real secrets out of git — only .env.example is ever tracked.

  1. Create the common templates from .env.example.

    Terminal window
    cp .env.example Admin-Local/1-Project/2-Vault/.env.local
    cp .env.example Admin-Local/1-Project/2-Vault/.env.staging
    cp .env.example Admin-Local/1-Project/2-Vault/.env.production
    # For additional Zaj-PROJECT.md rows, copy one file per env key:
    # cp .env.example Admin-Local/1-Project/2-Vault/.env.qa
    # cp .env.example Admin-Local/1-Project/2-Vault/.env.client-demo
    # Expected: .env.<environment-key> files created in the vault
    • .env.local, .env.production, and one .env.<env-key> for each real non-production row exist in the vault.
  2. Customize each template with runnable sed blocks — paste real secrets from the password manager; never commit filled vault files.

    Local (Admin-Local/1-Project/2-Vault/.env.local):

    Terminal window
    sed -i '' \
    -e 's/^APP_NAME=.*/APP_NAME="[PROJECT]"/' \
    -e 's/^APP_ENV=.*/APP_ENV=local/' \
    -e 's/^APP_DEBUG=.*/APP_DEBUG=true/' \
    -e 's|^APP_URL=.*|APP_URL=https://[project].test|' \
    -e 's/^DB_DATABASE=.*/DB_DATABASE=[project]_local_db/' \
    -e 's/^DB_USERNAME=.*/DB_USERNAME=[project]_local_user/' \
    -e 's/^DB_PASSWORD=.*/DB_PASSWORD=<FROM_SEEDED_LOCAL_ITEM_OR_VAULT>/' \
    Admin-Local/1-Project/2-Vault/.env.local
    # Expected: grep APP_ENV=local and APP_DEBUG=true in .env.local

    Non-production target (example env key: staging; use the real key and URL from Zaj-PROJECT.md):

    Terminal window
    ENV_KEY="staging"
    NON_PROD_URL="https://nonprod.example.com"
    sed -i '' \
    -e "s/^APP_NAME=.*/APP_NAME=\"[PROJECT] ${ENV_KEY}\"/" \
    -e "s/^APP_ENV=.*/APP_ENV=${ENV_KEY}/" \
    -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' \
    -e "s|^APP_URL=.*|APP_URL=${NON_PROD_URL}|" \
    -e "s/^DB_DATABASE=.*/DB_DATABASE=[project]_${ENV_KEY}_db/" \
    -e "s/^DB_USERNAME=.*/DB_USERNAME=[project]_${ENV_KEY}_user/" \
    -e 's/^DB_PASSWORD=.*/DB_PASSWORD=<FROM_SEEDED_ENV_ITEM_OR_VAULT>/' \
    -e 's/^SESSION_SECURE_COOKIE=.*/SESSION_SECURE_COOKIE=true/' \
    "Admin-Local/1-Project/2-Vault/.env.${ENV_KEY}"
    # Expected: APP_DEBUG=false and SESSION_SECURE_COOKIE=true

    Production:

    Terminal window
    sed -i '' \
    -e 's/^APP_NAME=.*/APP_NAME="[PROJECT]"/' \
    -e 's/^APP_ENV=.*/APP_ENV=production/' \
    -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' \
    -e 's|^APP_URL=.*|APP_URL=https://[DOMAIN]|' \
    -e 's/^DB_DATABASE=.*/DB_DATABASE=[project]_production_db/' \
    -e 's/^DB_USERNAME=.*/DB_USERNAME=[project]_production_user/' \
    -e 's/^DB_PASSWORD=.*/DB_PASSWORD=<FROM_SEEDED_PRODUCTION_ITEM_OR_VAULT>/' \
    -e 's/^LOG_LEVEL=.*/LOG_LEVEL=error/' \
    -e 's/^SESSION_SECURE_COOKIE=.*/SESSION_SECURE_COOKIE=true/' \
    Admin-Local/1-Project/2-Vault/.env.production
    # Expected: APP_DEBUG=false, LOG_LEVEL=error, SESSION_SECURE_COOKIE=true

    On Linux, use sed -i without the empty string after -i.

    • ✅ Each template carries this project’s values, with secrets pasted only into the gitignored variants.
  1. Activate the local env and generate its key.

    Terminal window
    cp Admin-Local/1-Project/2-Vault/.env.local .env
    php artisan key:generate
    # Expected: INFO Application key set successfully.
    • grep -qE '^APP_KEY="?base64:' .env returns 0 — the key line matches whether or not the value is double-quoted (quoting secrets is safe and recommended).

The same keys take different values per environment. The ones that matter most:

VariableLocalNon-production target(s)Production
APP_ENVlocalenv key from Zaj-PROJECT.mdproduction
APP_DEBUGtruefalsefalse
APP_URLhttps://app.testURL from Zaj-PROJECT.mdhttps://x.com
APP_KEYuniqueuniqueunique
LOG_LEVELdebuginfoerror
MAIL_MAILERlogsmtpsmtp
SESSION_SECURE_COOKIEfalsetruetrue

Run after all templates exist and local is active.

Terminal window
echo "=== Env template verification ==="
ls -1 Admin-Local/1-Project/2-Vault/.env.* 2>/dev/null
# Quote-tolerant value greps below: an optional double-quote may sit right after
# the `=` because quoting secret values is safe and recommended (and mandatory in
# some project rules). Each check matches the value whether or not it is quoted.
grep -qE '^APP_KEY=("")?$' .env.example && echo "✅ .env.example has empty APP_KEY" || echo "❌ scrub secrets from .env.example"
git check-ignore -q .env && echo "✅ live .env ignored" || echo "❌ add .env to .gitignore"
grep -qE '^APP_DEBUG="?false"?' Admin-Local/1-Project/2-Vault/.env.production && echo "✅ production debug off" || echo "❌ fix production APP_DEBUG"
for env_file in Admin-Local/1-Project/2-Vault/.env.*; do
case "$env_file" in
*.local|*.vendor-*|*.vendor-original|*.vendor-example) continue ;;
esac
grep -qE '^APP_DEBUG="?false"?' "$env_file" && echo "✅ $env_file debug off" || echo "❌ fix $env_file APP_DEBUG"
grep -qE '^SESSION_SECURE_COOKIE="?true"?' "$env_file" && echo "✅ $env_file secure cookies" || echo "⚠ set SESSION_SECURE_COOKIE in $env_file"
done
grep -qE '^APP_KEY="?base64:' .env && echo "✅ local APP_KEY set" || echo "❌ run php artisan key:generate"
# Expected: all ✅ lines; no real .env in git status
  • ✅ Vault holds the local, production, and non-production environment templates; .env.example has empty secrets; live .env is gitignored; remote templates differ from local on debug and secure cookies.

Do not mark this step done until every box below is checked.

  • 🤖 Vendor env backed up.env / .env.example copied to the vault.
  • 🤖 Credential items existLocal, Staging, and Production 1Password items were seeded in Prerequisites and use the flat field set.
  • 🔀 Templates created.env.local, .env.production, and one .env.<env-key> for each real non-production row exist in the vault.
  • 🤖 Local active + keyed.env active and a unique APP_KEY generated (grep -qE '^APP_KEY="?base64:' .env — passes whether or not the value is quoted).
  • 👤 Off-local debug off — every non-local template sets APP_DEBUG=false.
  • 🤖 No secrets stagedgit status shows no real .env files staged.