Infisical Community Edition is the secrets vault for the entire p24-infra ecosystem. All other services (monitoring stack, n8n, audit-engine, GitHub Actions workflows) draw credentials from it via Machine Identity Universal Auth.
Three containers form the stack:
Container
Image
Role
monitoring-infisical-1
infisical/infisical:v0.161.0
API + web UI
monitoring-infisical-postgres-1
postgres:16.9-alpine
Secret storage (encrypted)
monitoring-infisical-redis-1
redis:7.4.2-alpine
Session cache
Projects (Infisical slugs):
Project slug
Used by
MI env var prefix
p24-monitoring-f5de
vps-i1 monitoring stack + audit-engine
INFISICAL_MI_P24_MONITORING_*
n8n-bms4-ywf-z (latest)
bms-4 n8n stack
INFISICAL_MI_N8N_BMS4_*
vps-h1-ntjx (latest)
vps-h1 WAHA stack
INFISICAL_MI_VPS_H1_*
bms-servers-mq-he (latest)
BMS server agents
INFISICAL_MI_BMS_SERVERS_*
github-actions-s-m15
All GitHub Actions workflows
INFISICAL_MI_GITHUB_ACTIONS_*
art-agency
Art Agency portal (Supabase, PayPal, KDP, Google Drive)
INFISICAL_MI_ART_AGENCY_*
radekkonarski-brand
Radek personal brand (LinkedIn, HeyGen, Wasabi, n8n, Anthropic)
ENCRYPTION_KEY + JWT secrets extracted from container
monitoring.env
$WORK/monitoring.env
Full monitoring stack env (all credentials)
Destination:s3://ecotrans-backups/vps-i1/<YYYY-MM-DD>/backup.tar.zst.age Encryption: age (recipient = AGE_PUBKEY from /root/.backup-env) Retention: 30 days daily (managed by backup-common.sh parent job)
Critical: ENCRYPTION_KEY
The INFISICAL_ENCRYPTION_KEY env var is the AES master key that encrypts every secret value in the database. Without it, the database dump cannot be decrypted. It is captured two ways:
infisical-keys/infisical-env.txt — extracted from the running container
monitoring.env — full env file snapshot
Both are inside the age-encrypted archive, so the age private key (stored externally) is the single recovery prerequisite.
Age private key storage
The age private key is not stored on any VPS. It must be kept in an offline/out-of-band secret store (e.g. Bitwarden vault, paper backup, GPG-encrypted USB). Without it the backup archive cannot be decrypted.
A running Docker host with monitoring/docker-compose.yml deployed (vps-i1 or replacement)
Step 1 — Download and decrypt archive
# Install age and aws CLI if not presentapt-get install -y age awscli zstd# Download the backupaws --endpoint-url https://s3.eu-central-1.wasabisys.com \ s3 cp "s3://ecotrans-backups/vps-i1/<DATE>/backup.tar.zst.age" /tmp/backup.tar.zst.age# Decrypt and extractage -d -i /path/to/age-private-key /tmp/backup.tar.zst.age \ | zstd -d \ | tar -xf - -C /tmp/restore/
Step 2 — Recover INFISICAL_ENCRYPTION_KEY
# The key is in either of:cat /tmp/restore/infisical-keys/infisical-env.txt # extracted varsgrep INFISICAL_ENCRYPTION_KEY /tmp/restore/monitoring.envgrep INFISICAL_JWT /tmp/restore/monitoring.env
Note these values — you will need them in Step 4.
Step 3 — Start a fresh Infisical stack with the original keys
Ensure monitoring/.env on the recovery host contains the original values from /tmp/restore/monitoring.env. The critical vars are:
cd /opt/p24-infra/monitoringdocker compose up -d infisical-postgres infisical-redis# Wait for postgres healthydocker compose ps
Step 4 — Restore the database dump
# Copy dump into a temp location accessible by the containerdocker cp /tmp/restore/infisical_postgres.dump monitoring-infisical-postgres-1:/tmp/restore.dump# Drop and recreate the databasedocker exec -it monitoring-infisical-postgres-1 psql -U infisical -c "DROP DATABASE IF EXISTS infisical;"docker exec -it monitoring-infisical-postgres-1 psql -U infisical -c "CREATE DATABASE infisical;"# Restoredocker exec -it monitoring-infisical-postgres-1 \ pg_restore -U infisical -d infisical --no-owner --no-acl /tmp/restore.dump# Clean updocker exec monitoring-infisical-postgres-1 rm /tmp/restore.dump
Step 5 — Start Infisical and verify
docker compose up -d infisicalsleep 30docker compose ps # infisical should be healthy# Smoke test: health endpointcurl -k https://infisical.vps-i1.infra.zintegrowana.online/api/status# Expected: {"date":"...","message":"OK","..."}
Step 6 — Test Machine Identity auth
# From vps-i1 — test p24-monitoring MIsource /opt/infisical/monitoring.envcurl -sk -X POST "$INFISICAL_URL/api/v1/auth/universal-auth/login" \ -H 'Content-Type: application/json' \ -d "{\"clientId\":\"$INFISICAL_CLIENT_ID\",\"clientSecret\":\"$INFISICAL_CLIENT_SECRET\"}" \ | python3 -c "import sys,json; t=json.load(sys.stdin); print('OK' if t.get('accessToken') else 'FAIL')"
Step 7 — Restart all dependent services
# Restart monitoring stack to pick up Infisical secretscd /opt/p24-infra/monitoring./start.sh # re-runs infisical run -- docker compose up -d# On bms-4: restart n8n stackssh root@54.36.123.110 "cd /root && bash /root/start.sh"
4. Encryption key rotation
Machine Identity client secrets do not expire. Rotate manually if a MI is compromised:
Log in to Infisical UI → Settings → Machine Identities → select identity → Regenerate secret
Update the credential in the affected service’s env:
vps-i1 monitoring: update INFISICAL_CLIENT_SECRET in /opt/infisical/monitoring.env and restart
bms-4 n8n: update INFISICAL_CLIENT_SECRET in /opt/infisical/n8n.env and restart
Update .env.local on the developer workstation
INFISICAL_ENCRYPTION_KEY rotation requires decrypting and re-encrypting all secrets — do not rotate unless the key is confirmed compromised. Contact the Infisical CE docs for the rotation procedure.
5. Day-to-day: adding or rotating a secret
Step-by-step
Log in to the Infisical UI → select the correct project → production environment.
Add or update the secret.
Regenerate .env.bak on vps-i1 — this is mandatory after every secret change:
Replace <service> with the container name, e.g. alertmanager, cost-exporter, grafana.
Omit --no-deps and the service name to restart the entire stack.
If the secret also belongs to another project (n8n-bms4, vps-h1, github-actions) — update it there too and trigger that stack’s regen (see project table below).
ssh root@54.36.123.110 "bash /opt/infisical/regen-n8n-envbak.sh"(if it exists — see note)
vps-h1
vps-h1
ssh root@72.60.32.61 "bash /root/start.sh" — start.sh re-fetches from Infisical
github-actions
N/A
Run scripts/sync-github-secrets.ps1 or push to main (CI syncs automatically)
Note:/opt/infisical/regen-n8n-envbak.sh on bms-4 mirrors the same logic as the monitoring script. If it doesn’t exist yet, create it from scripts/regen-monitoring-envbak.sh adapting the monitoring.env path to /opt/infisical/n8n.env and the output path to /root/.env.bak.
6. Vault coverage and exceptions
Infisical CE is the single source of truth for all p24-infra credentials. Every secret that flows into a running container or script must live in Infisical first.
Developer workstation local override and rotation scratch-pad
Local file — not committed. Synced manually from Infisical or updated during rotation scripts
secrets/*.sops.yaml
Legacy SOPS-encrypted files from before Infisical rollout (2026-06). May contain stale values.
Git repo (encrypted). No longer the source of truth — migrate any remaining active secrets to Infisical and archive these files
Age private key
Required to decrypt SOPS backup archives — cannot be stored in Infisical
Bitwarden vault / offline backup (never on any VPS)
monitoring/.env.bak
Derived cache generated from Infisical — not a primary store
vps-i1 /opt/p24-infra/monitoring/.env.bak — regenerate after every Infisical change (see §5)
SOPS migration status
The secrets/*.sops.yaml files are legacy. After the Infisical rollout (2026-06-16), all active secrets should be in Infisical. The SOPS files are kept as a historical reference and for the age-encrypted Wasabi backup restore path. Do not add new secrets to SOPS files — add them to Infisical instead.
7. Health monitoring
Infisical is monitored via its Docker health check (wget -qO- http://localhost:8080/api/status). The Grafana monitoring stack scrapes container states via cAdvisor.
Current gaps:
No dedicated Prometheus exporter for Infisical secret-access metrics
Backup success is tracked via backup_last_success_timestamp metric on vps-i1