Secrets

Secrets are named, encrypted bags of key/values (AES-256-GCM at rest) that you reference from apps by name. The API never returns the values — only the key names. This is the right place for database URLs, API keys, tokens, etc. (better than inline env).

Two ways an app consumes a secret

Mode Field Result in the container
Env vars envFrom each key becomes an environment variable
Files secretFiles each key is mounted read-only at /run/secrets/<KEY> (in RAM, never on disk)

You can use either or both, at the app level (applies to all services) or per service.

Shared vs app-scoped

  • Shared (org-wide): available to every app in your org.
  • App-scoped: tied to one app by name. If a shared and an app-scoped secret share the same name, the app-scoped one wins for that app.

Create a secret

Dashboard

Secrets panel → name + key/value pairs → pick Scope (Shared or a specific app) → Save secret. Values are shown as password fields and never displayed again.

API

# shared (org-wide)
curl -s -X POST $API/secrets \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{"name":"db-creds","data":{"DATABASE_URL":"postgres://u:p@host/db"}}'

# scoped to a specific app (by app name)
curl -s -X POST $API/secrets \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{"name":"db-creds","data":{"DATABASE_URL":"postgres://…/app1"},"appId":"app1"}'

POST /secrets creates or replaces the secret of that name+scope.

Use it in a deploy

# inject as env vars + mount one key as a file
curl -s -X POST $API/deploy \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{
    "name":"api", "image":"acme/api:1.0", "port":3000,
    "envFrom":["db-creds"],
    "secretFiles":["tls-bundle"]
  }'
  • envFrom injects every key of db-creds as environment variables.
  • secretFiles mounts every key of tls-bundle at /run/secrets/<KEY> (read-only, RAM).

In the dashboard, the deploy form has Inject as env vars and Mount as files checkbox selectors listing your secrets.

Referencing a secret that doesn’t exist fails fast with 400 unknown_secret and the list of missing names.

Precedence (when keys collide)

Merged in this order, later wins (K8s envFrom semantics):

  1. app-level envFrom secrets
  2. per-service envFrom secrets
  3. inline env (always wins)

And for any single name, an app-scoped secret beats a shared one.

List / delete

curl -s $API/secrets -H "authorization: Bearer $TOKEN"           # names + key names only
curl -s -X DELETE "$API/secrets/db-creds" -H "authorization: Bearer $TOKEN"          # shared
curl -s -X DELETE "$API/secrets/db-creds?appId=app1" -H "authorization: Bearer $TOKEN" # scoped

If deploys return 503 sealed

The platform can run with its master key held only in memory (“sealed”). When sealed, /deploy and /secrets return 503. An operator unseals it with POST /admin/unseal (see Troubleshooting). On the default setup this is automatic and you’ll never see it.

→ Use them when deploying: Deploy a Docker Image, Multi-Service Apps


This site uses Just the Docs, a documentation theme for Jekyll.