Penv Cloud
Start free
Docs
Guidesince 1.0.0-alpha.3

Run in a container

Copy penv into your image from ghcr.io/penvhq/penv, pass a credential at run time, handle the per-start read, or ship an encrypted bundle instead.

A container has no keychain, so penv keeps no local copy and reads from us on every start. See local and cloud modes.

Image

Dockerfile
FROM node:22-slim
COPY --from=ghcr.io/penvhq/penv:1.0.0 /penv /usr/local/bin/penv
WORKDIR /app
COPY . .
ENTRYPOINT ["penv", "run", "--"]
CMD ["node", "server.js"]

ghcr.io/penvhq/penv (since 1.0.0-beta.2) is a scratch image holding the release-signed static binary at /penv, amd64 and arm64, with penv's own TLS roots. A prerelease is tagged with its version and next only.

Installer route: install the CLI (PENV_ALLOW_ROOT=1 under docker build).

Credential

docker run --rm -e PENV_TOKEN="$PENV_TOKEN" my-app:latest

PENV_TOKEN takes precedence over every other credential source. Issue a pck_ credential in the console, or avoid a long-lived one:

HostCredential source
Presents a platform tokenPut it in PENV_OIDC_TOKEN. See Kubernetes.
Proves nothingUse PENV_TOKEN: enrollment needs an OS keychain.
ECS task role, EKS IRSA, EKS Pod Identitypenv 1.0.0-beta.3 and later sign your workspace id, and we accept the exchange; 1.0.0-beta.2 does not, so use PENV_TOKEN there. See authenticate an AWS workload.

Never bake a credential or a .env into an image layer. Anyone who can pull your image can read every layer, and deleting a file in a later layer does not remove it from an earlier one.

Network at start

If penv cannot reach us, the start stops with exit code 5; your program never starts on stale values.

Point the readiness probe at the application so the orchestrator retries a failed start. An exchanged credential lives 15 minutes; penv run reads once and the child runs indefinitely.

TLS-inspecting proxy

docker run --rm -v /etc/ssl/certs/ca-certificates.crt:/ca.pem:ro -e SSL_CERT_FILE=/ca.pem my-app:latest

Since 1.0.0-beta.2, SSL_CERT_FILE replaces penv's built-in roots with the PEM bundle it names. In an agent session penv refuses a bundle you can write.

Encrypted bundle

penv bundle --env production    # writes .penv/production.bundle, prints PENV_BUNDLE_KEY=<hex> once
docker run --rm -e PENV_BUNDLE_KEY="$PENV_BUNDLE_KEY" my-app:latest

penv bundle (since 1.0.0-beta.2) seals one environment into a file you ship in the image. With PENV_BUNDLE_KEY set, penv run opens it instead of reading from us. A missing or unopenable bundle exits 3 (no_bundle, bundle_unreadable). A rotated value needs a new bundle and image.

File-only tools

penv pull

penv pull writes a plain .env at mode 0600, adds it to .gitignore, and skips dynamic values. Under a coding agent it exits 2.

penv pull inside docker build writes values into an image layer. Run it at container start, or in a build step whose output is not the image.

Setup

Copy /penv from ghcr.io/penvhq/penv into your image.

Set the entrypoint to penv run --.

Give the host an identity to exchange, or issue a pck_ credential in the console.

Pass it as PENV_TOKEN at run time.

Start the container and read stderr. Exit code 5 means penv could not reach us or found no credential.