Environment Variables
Managing production secrets and configuration
Where Variables Live
Production variables are stored on the server, per application, in /opt/frankendeploy/apps/<app>/shared/.env.local. The file is mounted read-only into the app and worker containers, survives deploys and rollbacks, and is never part of your repository.
Commands are run from the project directory: the application is the one in frankendeploy.yaml, the server is the argument.
What FrankenDeploy Sets for You
| Variable | Value |
|---|---|
APP_ENV | prod |
APP_DEBUG | 0 |
SERVER_NAME | :8080 (the port Caddy proxies to) |
DATABASE_URL | Generated and injected with a managed database (database.managed: true). With an external database, set it yourself |
SYMFONY_TRUSTED_PROXIES, TRUSTED_PROXIES | Private subnets, so Symfony trusts Caddy’s X-Forwarded-* headers (real client IP, HTTPS). Not injected when you define either one yourself. See Behind the Proxy |
The env.prod section of frankendeploy.yaml is not applied in production: it only feeds the generated compose.prod.yaml. Everything the app needs at runtime goes through the commands below.
Setting Variables
# Set a variable
frankendeploy env set prod MAILER_DSN="smtp://user:pass@smtp.example.com:587"
# Apply it right away with a rolling restart (see below)
frankendeploy env set prod MAILER_DSN="smtp://..." --reload
Without --reload, the change applies at the next deployment.
Secrets: use --from-stdin
Passing a secret as KEY=value leaves it in your shell history. With --from-stdin, the value never touches it:
# Interactive: hidden prompt
frankendeploy env set prod APP_SECRET --from-stdin
# Scripted: pipe the value
openssl rand -hex 32 | frankendeploy env set prod APP_SECRET --from-stdin
deploy refuses to start when APP_SECRET is missing (or DATABASE_URL with an external database), and offers to generate APP_SECRET for you in interactive mode.
Listing and Reading
frankendeploy env list prod # all variables, sensitive values masked
frankendeploy env get prod DATABASE_URL
Values of keys containing SECRET, PASSWORD, PASS, KEY, TOKEN, DSN or DATABASE_URL are masked in env list and in --verbose output; env get shows the full value.
Removing
frankendeploy env remove prod OLD_VARIABLE
Bulk Operations
Push a .env file
Variables of a local file are merged into the server’s .env.local (existing keys are overwritten, others kept):
frankendeploy env push prod .env.prod
frankendeploy env push prod .env.prod --reload
Only files named .env* are accepted.
Pull from the server
frankendeploy env pull prod
# writes .env.prod.backup (permissions 600) in the current directory
The file is named after the server (.env.<server>.backup). Do not commit it.
Zero-Downtime Updates
--reload restarts the application without dropping a request, with the same mechanism as a deploy:
- A new container starts with the updated
.env.local, on the same image - FrankenDeploy waits for its health check
- Traffic switches to it (rename-based swap)
- The old container is stopped
If the new container never becomes healthy, it is removed and the old one keeps serving.
Required Variables
| Variable | Notes |
|---|---|
APP_SECRET | Required by Symfony. Checked before every deploy |
DATABASE_URL | Injected automatically with a managed database. Required, and checked, with an external one |
MAILER_DSN, MESSENGER_TRANSPORT_DSN, … | Whatever your config/packages/*.yaml reference through %env()% |
Security Notes
- Every write (
env set,env push,env remove, credentials generated by a deploy) enforceschmod 600on the server file - The file is mounted read-only into the containers
- Secrets are never written to
frankendeploy.yamlor transmitted through Git - Sensitive values are masked in
env listand in verbose logs (same detection list for both) - The file is stored in clear on the server disk, protected by its permissions: anyone with root or SSH access to the server can read it. Encrypting it there would not help, since the key would sit next to it. Use your provider’s disk encryption for backups and snapshots
- The Symfony secrets vault works as usual: commit the vault, set only
SYMFONY_DECRYPTION_SECRETwithenv set --from-stdin
Workflow Example
# 1. Production secrets, once
openssl rand -hex 32 | frankendeploy env set prod APP_SECRET --from-stdin
frankendeploy env set prod MAILER_DSN --from-stdin
# 2. Deploy
frankendeploy deploy prod
# 3. Later, change a value without downtime
frankendeploy env set prod FEATURE_FLAG=enabled --reload