Secrets & environment
How HostSSH delivers environment variables and secrets to your apps — sealed at rest, decrypted only inside the agent, editable after deploy.
Secrets & environment
Every App gets configuration through environment variables. HostSSH splits them into two kinds and treats secrets very differently from plain values.
- Plain env — non-sensitive values:
NODE_ENV=production, feature flags, public URLs. - Sealed secrets — sensitive values:
DATABASE_URL, API keys, tokens, signing keys.
The rule: secret values never travel or rest in plaintext. They're sealed by the control plane and decrypted only inside the Agent, at deploy time.
1. Setting env when you deploy
Dashboard: in the Deploy drawer, add variables in the Environment section. Mark the sensitive ones as secret — those get the sealed treatment.
CLI:
$ hostssh deploy --name shop --source ./shop \
--env NODE_ENV=production \
--env-file ./shop.env
--env K=Vsets one variable (repeatable).--env-file freadsKEY=VALUElines from a file; individual--envflags override it.
For the CLI, treat any file you pass with --env-file as sensitive and keep it out of version
control.
2. Env lives on the App and survives redeploys
Environment is attached to the App — the stable deployment row in the control plane — not to a particular container. So:
- A redeploy keeps your env. You don't re-enter it every time.
- Editing env is a first-class action. Go to App Settings → Environment Variables, change values, and click Save. The change is stored immediately; click Redeploy to apply to roll it into the running container.
This is why the platform can guarantee env doesn't silently vanish on a clean redeploy (guard G3).
3. Bulk editing: paste a whole .env
You never have to enter variables one at a time:
- Paste to expand. Paste a multi-line
.envblob into any KEY field and it expands into rows. Comments, blank lines,exportprefixes, and quoted values are all understood; existing keys update in place and new keys append. A pastedKEY=with no value leaves a stored secret untouched. - Raw .env mode. Click Raw .env to edit the whole set as one text file — ideal for bulk
reorder, delete, or paste. Secret and auto values appear as
KEY=(their stored values are kept; they are never sent to the browser). Deleting a line deletes the variable. - Copy .env. One click copies everything in
.envformat for local dev or migration. Values the server holds sealed are exported asKEY=— secret material never leaves the platform this way. - Auto-minted secrets. Toggle a row to auto and the Agent mints a strong random value
directly on the Node at deploy time — perfect for
SESSION_SECRET-style values nobody needs to know. The value is never entered, stored in the control plane, or dispatched; it stays stable across redeploys.
4. How sealed secrets work (the security model)
When you mark a value secret, here's its journey:
- Sealed at the control plane. The value is encrypted (AES-GCM) into an envelope before it's ever written to the database. The database stores the envelope; the plaintext is never persisted, and the value is masked in every UI.
- Queued sealed. When a deploy Job is created, plain env goes in a public
envfield and secrets go in a separatesecretEnvfield as sealed envelopes. The job queue and its logs never contain plaintext secrets. (The system actively rejects a job that tries to carry a plaintextsecretEnv.) - Decrypted only inside the Agent. The Agent holds the decryption key (
HOSTSSH_ENC_KEY) in its own environment. It opens the envelopes at deploy time, merges the secret values into the container's runtime environment, and persists them to a local0600secret store so redeploys and restarts don't need the control plane to re-send them. - Never in logs. Deploy logs, job status, and dispatch payloads carry only masked references for secret values.
The consequence: someone with read access to the control-plane database, the job queue, or the deploy logs still cannot read your secrets. Only the Agent on the box — which is already the thing running your code — can.
The key that unlocks it:
HOSTSSH_ENC_KEYis what seals and opens envelopes. Keep it consistent across your control plane and Agents, and back it up. If you ever move the control plane to a new machine, carry this key byte-for-byte — otherwise previously sealed secrets can't be decrypted. (Seedocs/dev/security-model.md.)
5. Where secrets should point (the private Mesh)
Your DATABASE_URL and other internal endpoints should use private Mesh addresses, not public
IPs. HostSSH links your Nodes over a private WireGuard network, so an App on one Node reaches
Postgres on another over 10.x addresses that are never exposed to the internet. For example:
DATABASE_URL=postgres://app:••••@10.10.0.2:5432/shop
This keeps your database off the public internet entirely. See Concepts and Databases (in Backups & recovery).
6. Storing provider credentials (BYOK connections)
Secrets that aren't app env — your R2/S3 keys, Cloudflare tokens, Hostinger API token — belong in the Connections vault, not in an App's env. They're sealed the same way and reused across features (backups to your bucket, DNS cutovers, provisioning). See Connections (BYOK).
7. Good habits
- Mark anything sensitive as secret. When in doubt, seal it. There's no downside.
- Use the Mesh for internal endpoints. Don't put a public database IP in an env var.
- Rotate by editing + redeploying. Change the value in App Settings, redeploy, then revoke the old credential at its source.
- Keep
HOSTSSH_ENC_KEYand your license key backed up off the box (HostSSH can age-encrypt an off-box copy of platform secrets for you — see Backups & recovery). - Never commit env files. Add
.env,*.env, and any--env-filetargets to.gitignore.
Next steps
- Wire up a database over the Mesh → Backups & recovery
- Store R2/Cloudflare creds → Connections (BYOK)