Sthora
Deploying applications

Environment variables

Write-only values, encrypted at rest under a key outside the database, scrubbed from build logs, and never written to disk.

Write-only, by contract

You can set a variable and you can delete it. You cannot read one back — not through the portal, not through the API, not as an operator.

GET /applications/:id/variables returns the key, whether it is a build argument, and the value's length. There is no field in the response contract that could carry a plaintext value, so no handler can leak one by forgetting to strip it. valueLength exists so the portal can render "32 characters" and confirm a value is set without revealing it.

Keys

^[A-Za-z_][A-Za-z0-9_]*$

Letters, digits, and underscores, starting with a letter or underscore, up to 128 characters. That is the shape a shell will actually export. Compose interpolates ${NAME} using this character set, and a key outside it produces a variable your container cannot read — a failure that looks like the platform dropped the value.

Values are up to 32 KB.

Runtime values and build arguments

RuntimeBuild argument
FlagisBuildTime: false (default)isBuildTime: true
ReachesThe running container's environmentThe image build
Baked into the image layerNoYes
Injected as${ST_ENV_<KEY>}${ST_ARG_<KEY>}, on the exposed service's build

A build argument is baked into the image layer. Anyone who can pull or inspect the image can read it. Put credentials in runtime values, never in build arguments.

How a value reaches your container

At rest. AES-256-GCM, keyed from SECRET_ENCRYPTION_KEY_FILE (preferred) or SECRET_ENCRYPTION_KEY. The stored form is v1.<nonce>.<tag>.<ciphertext>, base64url.

Into the rendered compose file. As a reference — ${ST_ENV_DATABASE_URL} — never as the value.

Into Docker. Through the environment of the docker compose process itself. The plaintext is never written to any file on the server.

Out of the logs. Values are scrubbed at the single point every build-log line passes through, so a build that echoes its environment does not publish it.

The master key

The key lives outside the database, in a file the installer writes at mode 0600.

openssl rand -hex 32 > /etc/sthora/master.key && chmod 600 /etc/sthora/master.key
# then set SECRET_ENCRYPTION_KEY_FILE=/etc/sthora/master.key

Back it up off the box

Losing the master key makes every stored value unrecoverable — variables, deploy-key private halves, webhook secrets, and managed-service credentials. The database alone will not restore them.

The file form is preferred over SECRET_ENCRYPTION_KEY because an environment variable is readable through /proc, through docker inspect, and out of any crash dump that captures the environment.

With neither set, the API still starts and every route that does not touch a secret keeps working. The ones that do say exactly what is missing.

Changing a value

Setting a variable does not restart anything. The new value reaches the container on the next deployment — or on a restart, which re-runs docker compose up with the current environment.

On this page