The Tinfoil CLI ships with the same container management surface as the dashboard. Anything you can do in the Tinfoil Containers UI — create, start/stop, update, manage secrets, SSH keys, registry credentials, and custom domains — has a CLI equivalent.
This page walks through the full container lifecycle from the terminal.
Prerequisites
Install the CLI:
curl -fsSL https://github.com/tinfoilsh/tinfoil-cli/raw/main/install.sh | sh
Or download a binary from the releases page. A Docker image is published at ghcr.io/tinfoilsh/tinfoil-cli.
You also need a Tinfoil organization with Containers enabled, the same prerequisite as the quickstart.
Authenticating
Container management endpoints accept an admin API key scoped to a single organization. Create one in the Tinfoil Dashboard under Settings → API Keys → Admin keys, then run:
tinfoil login # prompts for the key (no shell history)
tinfoil login --api-key admin_xxx # non-interactive, e.g. for CI
tinfoil whoami # confirm the saved credential
tinfoil logout # delete the saved credential
Credentials are written to ~/.tinfoil/config.json with mode 0600. Two environment variables override the saved values for one-off invocations:
| Variable | Purpose |
|---|
TINFOIL_API_KEY | Admin key (admin_...) |
TINFOIL_CONTROLPLANE_URL | Controlplane URL (defaults to https://api.tinfoil.sh) |
Admin keys carry the organization ID, so the CLI never asks for an org. To act on a different org, log out and log in with that org’s admin key.
Inspecting your organization
tinfoil container list # all containers in the org
tinfoil container get my-app # full detail for one container
tinfoil container hosts # which container hosts your org may target
Pass -o json to get machine-readable output suitable for scripting:
tinfoil container list -o json | jq '.[] | select(.status == "failed")'
Containers can be referenced by name or UUID. If you have a debug-mode and a production-mode container with the same name, pass --debug-mode to disambiguate.
Deploying a container
Once you have a measured release in your config repo (see quickstart for the GitHub setup), deploy it:
tinfoil container create my-app \
--repo myorg/my-app-config \
--tag v1.0.0 \
--variable LOG_LEVEL=info \
--variable PORT=8080 \
--secret DATABASE_URL \
--custom-domain api.example.com
| Flag | What it does |
|---|
--repo | GitHub owner/repo containing tinfoil-config.yml (required) |
--tag | Release tag to deploy (required) |
--variable KEY=VALUE | Environment variable; repeatable |
--secret NAME | Org secret to mount; repeatable |
--ssh-key NAME | Org SSH key (debug containers only); repeatable |
--debug | Deploy in debug mode |
--staging | Deploy in staging mode |
--custom-domain | Use a verified custom domain |
--host | Pin to a specific host (see tinfoil container hosts) |
--replace ID | Atomically replace an existing container (frees its GPUs first) |
The command returns once the deployment is queued. Poll for readiness with tinfoil container get my-app.
Lifecycle
# Stop a running container (DB row preserved, traffic stops, billing pauses)
tinfoil container stop my-app
# Start a stopped container (optionally with config overrides)
tinfoil container start my-app
tinfoil container start my-app --tag v1.0.1
# Redeploy a running container with new config (blue-green)
tinfoil container relaunch my-app --tag v1.0.1
tinfoil container relaunch my-app --variable LOG_LEVEL=debug
tinfoil container relaunch my-app --secret NEW_KEY --secret OTHER_KEY
# Delete (irreversible)
tinfoil container delete my-app
relaunch and start accept the same overrides as create. Any flag you pass replaces the stored value entirely — for example, --secret A followed by --secret B sets the container’s secrets list to [A, B], not [A, B, ...existing].
tinfoil container delete permanently removes the container, its secret bindings, and its DNS records. There is no undo.
Managing in-progress updates
Updates triggered by relaunch, start, or auto-update on tag push go through a blue-green window. While the new version is booting, you can inspect or cancel it:
tinfoil container update status my-app # show update status (pending/started/ready/failed)
tinfoil container update accept my-app # promote a "ready" candidate
tinfoil container update cancel my-app # discard the candidate, keep current
Staging containers always wait for update accept; production containers promote automatically once the candidate is ready.
Auto-update
For GitHub-connected containers, you can have Tinfoil deploy every new release tag automatically:
tinfoil container auto-update my-app --on
tinfoil container auto-update my-app --off
See updates for what’s safe to auto-update.
Secrets
tinfoil secret list
# Create
tinfoil secret create DATABASE_URL --value-file ./db.url
echo -n "$STRIPE_KEY" | tinfoil secret create STRIPE_SECRET_KEY --value-file -
# Update value (containers using it are marked stale; redeploy to pick up the new value)
tinfoil secret set DATABASE_URL --value-file ./db.url
# Inspect (the value itself is never returned)
tinfoil secret get DATABASE_URL
# Delete (fails if any container references it)
tinfoil secret delete DATABASE_URL
--value-file accepts - for stdin, which is the recommended way to set secrets — it avoids leaking the value via shell history or process listings. See secrets and env vars for the underlying model.
SSH keys
Debug-mode containers authorize SSH access using public keys registered at the org level:
tinfoil ssh-key list
tinfoil ssh-key create laptop --public-key-file ~/.ssh/id_ed25519.pub
tinfoil ssh-key delete laptop
Reference keys at deploy time with --ssh-key NAME on tinfoil container create (or relaunch / start).
Registry credentials
For private images, set credentials per registry. Tinfoil supports ghcr, gcr, and dockerhub:
tinfoil registry list
# GitHub Container Registry: classic PAT with read:packages
tinfoil registry set ghcr --username my-gh-user --token ghp_xxx
# Google Artifact Registry / Container Registry: service-account JSON
tinfoil registry set gcr --key-file ./gcp-sa.json
# Docker Hub: PAT with read permission
tinfoil registry set dockerhub --username my-docker-user --token dckr_xxx
# Remove credentials for a registry
tinfoil registry delete ghcr
Custom domains
tinfoil domain list
# Register a domain — output includes the TXT/CNAME records to configure
tinfoil domain add api.example.com
# Re-check DNS after configuring records
tinfoil domain verify api.example.com
# Remove (fails if any container uses it)
tinfoil domain delete api.example.com
Once a domain is verified, deploy a container against it with tinfoil container create ... --custom-domain api.example.com. See custom domains for the DNS record details and troubleshooting.
Connecting to a deployed container
tinfoil container connect <name> resolves a container’s enclave domain and source repo, then runs a verified local proxy — equivalent to tinfoil proxy -e <domain> -r <repo> but without copy-pasting either value:
tinfoil container connect my-app -p 8080
In another terminal, send requests to http://localhost:8080 exactly as you would to your container’s domain. The proxy verifies attestation on startup and pins the TLS certificate for subsequent requests. See connecting for the full client story (SDKs, raw tinfoil http).
Debug-mode containers do not pass attestation, so connect (and any other SecureClient flow) will refuse to use them. SSH into debug containers directly via ssh -p <port> [email protected] — the dashboard shows the exact command on the container’s card.
Resource metrics
tinfoil container metrics my-app --time 24h
Returns CPU, GPU, and memory utilization buckets as JSON. Useful for piping into jq or a chart tool.
Scripting tips
-o json is supported on every list/get command.
- Exit codes are non-zero on failure, with the controlplane error message printed to stderr.
- All commands respect
TINFOIL_API_KEY / TINFOIL_CONTROLPLANE_URL, so the CLI is safe to use from CI — store the admin key as a secret and pass it through the environment instead of running tinfoil login.
--verbose and --trace increase log verbosity for debugging connectivity issues.