Option 1: Deploy token (recommended)
The same model as every managed platform. The droplet holds two environment variables and nothing else. On your laptop, in the project directory:--init so the container gets a real PID 1. capy run forwards SIGINT, SIGTERM, and SIGHUP to your process, but it is not a process reaper — pair it with Docker’s init if your app spawns children.
Neither value in that file is a secret on its own. SECRETS_BLOB is inert without a live call to the Capy service, the service refuses revoked tokens, and no plaintext ever touches the droplet’s disk.
To rotate: re-run capy deploy, replace the file, restart the container. To cut access: capy deploy revoke <deployId>.
Option 2: Droplet-resident identity
Sometimes you want the droplet to be a member of the org — every decryption attributed to a person, secrets updated withcapy the same way as on a laptop. This trades availability for auditability. Read the tradeoff before choosing it.
Logging in without a browser
capy signs in through your browser with a callback on localhost. A headless droplet has no browser, so forward the callback ports over SSH and use the browser you already have. The CLI takes the first free port in the range 19420–19424, so forward all five:
localhost, the tunnel carries it to the droplet, and the CLI completes the flow. You have five minutes before it times out.
This is a one-time step. Afterwards the droplet holds a session and refreshes it silently.
You now have keep.lock and an encrypted .env in /srv/myapp. Both are safe at rest — every value in .env is ciphertext.
Wrapping the container
capy run cannot inject into a container that is already running, so it has to be what launches the container:
capy run’s environment:
capy to pull the latest secrets, then capy run -- docker compose up -d.
Which one
The deciding question is what happens when the person leaves. With a droplet identity, their session ends and containers stop booting on their next restart — production is coupled to an individual’s account. Deploy tokens have no such coupling, which is why they are the default recommendation for anything load-bearing.
Both modes call the Capy service once at container start. If that call fails the container does not start, in exchange for revocation that takes effect on the very next boot rather than whenever a cached key expires. Once running, a service outage is invisible to your process.
See also
Docker
Entrypoint patterns, Compose, and Kubernetes.
capy run
What each mode needs at startup.