This guide covers installing and running a service from a published OCI image. You do not need the service source tree — the contract artifact is embedded in the image.
If you are developing a service locally and have the source checked out, see Install a service from source instead.
What you need
- a running Trellis environment
- the
trellisCLI installed (see Install the Trellis CLI) - admin access to the Trellis instance
- a published OCI image for the service (e.g.,
ghcr.io/my-org/my-service:1.2.3)
1. Log in as an admin
Create or refresh the local administrator session:
trellis --nats-servers localhost auth login \
--auth-url http://localhost:3000 \
--provider github Confirm the session is active:
trellis auth status 2. Install the contract from the image
trellis service install --image ghcr.io/my-org/my-service:1.2.3 The CLI pulls the image, reads the contract artifact from it (at the path declared by the io.trellis.contract.path label, or /trellis/contract.json by default), generates a session key, and installs the contract.
The CLI will:
- generate a new Ed25519 session seed locally
- derive the public session key for the service
- infer defaults such as display name, description, and namespaces from the contract
- show an installation review before sending the request
3. Store the seed immediately
After a successful install, the CLI prints:
installed service contract
sessionKey=<public-key>
contractId=trellis.my-service@v1
contractDigest=<digest>
seed=<private-seed>
store the seed securely; it will not be shown again Save the seed to your secret manager or deployment system immediately. The CLI will not print it again.
4. Run the container
Run the same image you installed from. Pass the session seed and NATS connection details as environment variables:
podman run --rm \
-e MY_SERVICE_SESSION_KEY_SEED="<seed from install>" \
-e NATS_SERVERS=host.containers.internal \
-e NATS_SENTINEL_CREDS=/run/creds/sentinel.creds \
-v /path/to/sentinel.creds:/run/creds/sentinel.creds:ro \
--network trellis.network \
ghcr.io/my-org/my-service:1.2.3 For a permanent deployment, create a Quadlet unit for the service similar to the runtime and console units in the Starting Trellis guide.
5. Upgrade to a new version
trellis service upgrade --image ghcr.io/my-org/my-service:1.2.4 If multiple installed services use the same contract id, target the correct one:
trellis service upgrade --image ghcr.io/my-org/my-service:1.2.4 --service-key <public-key> Upgrade keeps the service key the same and updates the installed contract digest. Restart the container with the new image tag after upgrading.
What install actually grants
Installation is not only metadata storage. It is the control-plane step that determines what the service is allowed to do.
Trellis derives service access from:
- the service-owned RPC, event, and subject surfaces declared in the contract
- explicit dependencies declared under
uses - runtime-managed resource bindings created during install or upgrade
Useful flags
| Flag | Command | What it does |
|---|---|---|
--display-name | service install | Overrides the default display name inferred from the contract |
--description | service install | Stores an explicit operator-facing description |
--namespace | service install | Adds extra namespaces beyond the ones inferred from the contract |
--inactive | service install | Installs the service in an inactive state |
-f | both | Skips the interactive confirmation prompt |
--service-key | service upgrade | Targets a specific installed service |
Practical deploy loop
trellis auth logintrellis service install --image ghcr.io/my-org/my-service:1.2.3- store the seed
- start the container with the right env
- confirm the expected RPCs, events, and bindings work
Install or upgrade should always happen before the container starts serving traffic.
If you are building service images, include the generated contract artifact at /trellis/contract.json. If the image uses a different path, add an OCI label such as io.trellis.contract.path=/path/to/contract.json so the CLI can discover it automatically.