Environment Variables
Compose files use environment variables for configuration. dockmesh extends this with global variables injected into every stack, plus host-scoped variables that only apply to stacks on specific hosts.
Precedence
Section titled “Precedence”When a stack deploys, dockmesh resolves variables in this order (highest wins):
- Stack
.envfile (in the stack directory on disk) - Organization globals from the Environment page (apply to every stack)
- Compose defaults (if the Compose file has
${VAR:-default})
This lets you set TZ=Europe/Berlin once as a global and have it injected into every container, while still overriding it per-stack via the stack’s own .env.
Host-tag-scoped globals (“only on hosts tagged prod”) are not implemented today — globals are organization-wide. The same goes for stack-level UI-managed variables: today the per-stack source is the .env file on disk.
Global variables
Section titled “Global variables”Environment in the sidebar manages organization-wide variables, grouped by a free-form group label (purely a UI organisation aid — groups do not change precedence or scope).
Common globals:
| Variable | Example | Why |
|---|---|---|
TZ | Europe/Berlin | Consistent timezone across containers |
PUID / PGID | 1000 / 1000 | LinuxServer.io convention for file ownership |
SMTP_HOST | mail.example.com | Shared email server across all apps |
LOKI_URL | http://loki:3100 | Shared log shipping |
SENTRY_DSN | https://... | Shared error tracking |
Secrets — work-in-progress
Section titled “Secrets — work-in-progress”The global_env schema has an encrypted boolean flag, but the UI doesn’t expose toggling it on import / edit yet — secrets land in the database as plaintext for now. The import preview heuristically flags keys matching password/secret/key/token as worth-marking-secret so you can see what would be encrypted once the backend slice lands. Until then, two pragmatic workarounds:
- Keep production secrets out of the dockmesh database entirely — use Docker’s native secrets or an external store (Vault, SOPS, age-encrypted files mounted in) and reference them in the compose file.
- Set the
encryptedflag directly via the REST API (PUT /api/v1/global-env/<id>) if you really need at-rest encryption today.
Tracked in the Slice-2 backend punch-list.
Access to env vars is gated on the system.update permission. There is no dedicated env.read_secrets role today — anyone with system.update sees the full value.
Import from .env file
Section titled “Import from .env file”Environment → Import accepts a standard .env file:
TZ=Europe/BerlinPUID=1000SMTP_HOST=mail.example.comDATABASE_PASSWORD=s3cr3tLines starting with # and blank lines are skipped. The preview shows the parsed keys, suggested-secret flags, and which keys would conflict with existing entries (those get skipped on apply).
A built-in Export to .env flow isn’t shipped — copy the values out via GET /api/v1/global-env if you need them for backup or migration.
Using in Compose
Section titled “Using in Compose”Reference globals like any env var:
services: app: image: nginx environment: - TZ - PUID - DATABASE_URL=postgres://user:${DATABASE_PASSWORD}@db/appShort form (- TZ) imports the variable by name from the environment. Long form with = uses interpolation.
Every change to a global variable is logged — who changed what, when, from where. Use this to trace “who changed the SMTP password at 2am”.
See also
Section titled “See also”- Stack Management — where stack-level
.envis edited - Audit Log — env var change history
- RBAC —
system.updatecovers global env management today