Playbook: s3-v2-v42-prod — Empty env vars / 403 Wasabi / CORS after deploy
Trigger
Any of:
- File download returns
{"code":"Forbidden","statusCode":403}in W4 - CORS errors for
/api/i18n/langs,/api/record-tag,/api/reg/*in W4 browser console EAI_AGAIN s3-v2-v42-prodin v42-prod logs- PM2 crash loop with
Error: bucket is required
Root cause pattern
docker restart / --restart unless-stopped does not re-read --env-file.
Env vars are baked at docker run time. The container may restart (crash loop, manual restart, OOM)
with stale env vars even though the source file on disk was updated.
Symptom chain
pinbox24PublicBucketName/pinbox24PublicOfficeAccessKeyIdempty in container → PM2 multer-s3 throwsError: bucket is required- Correct keys in
/opt/p24-infra/bms-1/pinbox24-w4.env(deployed by secrets-sync) but container was started before the file was populated → stale env frontendUrlmissing from container (only ins3-v2-environment.env, not inpinbox24-w4.env) → CORS failure on every API call that checks origin
Confirm it
# On bms-1 — no values printed, only counts
docker exec s3-v2-v42-prod printenv pinbox24PublicBucketName | wc -c # should be 29, not 1
docker exec s3-v2-v42-prod printenv frontendUrl | wc -c # should be 16, not 0
docker exec s3-v2-v42-prod printenv pinbox24PublicOfficeAccessKeyId | wc -c # should be 21
docker exec s3-v2-v42-prod env | grep -c pinbox24 # should be ~30If any value is 0 or 1 (empty), the container needs to be recreated.
Fix
Step 1 — verify source files have correct content
# Count length of key value in deployed file (safe — no value shown)
grep 'pinbox24PublicBucketName' /opt/p24-infra/bms-1/pinbox24-w4.env | cut -d= -f2- | wc -c
# Must be >5. If 1 (empty) → run secrets-sync first (see §Secrets-sync not run yet)Step 2 — fix env file permissions (if CI deploy will follow)
chown root:gitlab-runner /root/s3v2-prod/s3-v2-environment.env
chmod 640 /root/s3v2-prod/s3-v2-environment.envStep 3 — recreate container with both env files
docker stop s3-v2-v42-prod
docker rm s3-v2-v42-prod
docker run -d \
--name s3-v2-v42-prod \
--network test-net \
--restart unless-stopped \
--env-file /root/s3v2-prod/s3-v2-environment.env \
--env-file /opt/p24-infra/bms-1/pinbox24-w4.env \
-e CONTAINER_NAME=s3-v2-v42-prod \
-e NODE_ENV=production \
-e TZ=Europe/Warsaw \
-e PORT=3000 \
-e MAILGUN_USER_NAME=api \
-e VIRTUAL_HOST=s3-v2-api.w4.pinbox24.com \
-e LETSENCRYPT_HOST=s3-v2-api.w4.pinbox24.com \
-v /root/s3v2-prod/patches/mailgunFileHandler.helper.js:/app/dist/apps/storage/mailgunFileHandler.helper.js:ro \
-v /var/log:/var/log \
-v /root/s3v2-prod/persistent-patches/storage.controller.js:/app/dist/apps/storage/storage.controller.js:ro \
-v /root/s3v2-prod/persistent-patches/storage.config.js:/app/dist/config/storage.config.js:ro \
-v /root/s3v2-prod/persistent-patches/app.routing.js:/app/dist/app.routing.js:ro \
--log-opt max-size=10m \
--log-opt max-file=5 \
563740926945.dkr.ecr.eu-central-1.amazonaws.com/s3-v2-v42-prod:latest
# Connect to prod-v-4-net so v42-prod can resolve hostname
docker network connect prod-v-4-net s3-v2-v42-prod || trueStep 4 — verify
sleep 5
docker exec s3-v2-v42-prod printenv pinbox24PublicBucketName | wc -c # >=29
docker exec s3-v2-v42-prod printenv frontendUrl | wc -c # >=16
docker exec s3-v2-v42-prod pm2 status | grep online | wc -l # 4
docker network inspect prod-v-4-net | grep s3-v2-v42-prod # should appearSecrets-sync not run yet
If pinbox24-w4.env was recently updated in SOPS (new PR merged) but sync hasn’t run:
# From Windows dev machine
gh workflow run secrets-sync.yml --repo radieu/p24-infra -f target=pinbox24-w4
# Wait for completion, then check bms-1 file size (should grow after adding pinbox24Public* keys)Why two env files?
/root/s3v2-prod/s3-v2-environment.env— contains:frontendUrl,envirmnmentUrl,MONGODB_URI,SESSION_SECRET,port,monitoringToken,mailgunPassword,PM2_*. NOT in SOPS./opt/p24-infra/bms-1/pinbox24-w4.env— deployed by secrets-sync frompinbox24-w4.env.sops. Contains: allV42_*keys +pinbox24Public*Wasabi credentials.- Second file overrides first for any key that exists in both.
Long-term fix: migrate remaining keys from s3-v2-environment.env into pinbox24-w4.env.sops
so all secrets are SOPS-managed. Tracked in issue #3171.
Escalation
If container still crashes after recreation:
- Check
docker logs s3-v2-v42-prod --tail 50for startup errors - Check PM2 status:
docker exec s3-v2-v42-prod pm2 status - Verify storage.config.js patch uses
process.env.*not hardcoded keys:docker exec s3-v2-v42-prod grep -c 'process.env' /app/dist/config/storage.config.js→ should be ≥3 - If wkhtml EAI_AGAIN:
docker network connect test-net wkhtml-v42-prod || trueSee also:pinbox24-wkhtml-network-isolation.md
Prevention
- GitLab CI
.gitlab-ci.yml(master branch) now uses BOTH env files and addsprod-v-4-netconnect secrets-sync.ymlsync-pinbox24-w4deploys correct content to pinbox24-w4.env- File permissions:
640 root:gitlab-runneron both env files (set by secrets-sync + this playbook)