This page covers Docker setup, prebuilt binaries, cloud storage backends, and production deployment considerations for truss.
Download a prebuilt binary from the GitHub Releases page. Archives and SHA256 checksums are published for each release, along with release-manifest.json; see Downloading release binaries from a program for reading it from code.
Homebrew installs are published to nao1215/tap:
brew install nao1215/tap/truss| Target | Archive |
|---|---|
| Linux x86_64 | truss-v*-x86_64-unknown-linux-gnu.tar.gz |
| Linux aarch64 | truss-v*-aarch64-unknown-linux-gnu.tar.gz |
| macOS x86_64 | truss-v*-x86_64-apple-darwin.tar.gz |
| macOS aarch64 (Apple Silicon) | truss-v*-aarch64-apple-darwin.tar.gz |
| Windows x86_64 | truss-v*-x86_64-pc-windows-msvc.zip |
Example (Linux x86_64):
tar xzf truss-v*.tar.gz
sudo mv truss /usr/local/bin/docker compose upThis starts the server from compose.yml. The default configuration mounts ./images as the storage root.
docker build -t truss .
docker run -p 8080:8080 \
-e TRUSS_BIND_ADDR=0.0.0.0:8080 \
-e TRUSS_BEARER_TOKEN=changeme \
-v ./images:/data:ro \
-e TRUSS_STORAGE_ROOT=/data \
trussPrebuilt container images are published to GHCR:
docker pull ghcr.io/nao1215/truss:latesttruss supports multiple storage backends. The backend is selected via TRUSS_STORAGE_BACKEND. Only one backend can be active at a time. See the Configuration Reference for all storage-related environment variables.
# S3
cargo install truss-image --features s3
# Google Cloud Storage
cargo install truss-image --features gcs
# Azure Blob Storage
cargo install truss-image --features azure
# All storage backends
cargo install truss-image --features "s3,gcs,azure"Set TRUSS_STORAGE_BACKEND=s3 and configure:
| Variable | Description |
|---|---|
TRUSS_S3_BUCKET |
Default S3 bucket name (required) |
TRUSS_S3_FORCE_PATH_STYLE |
Use path-style addressing (true/1; required for MinIO, LocalStack, etc.) |
AWS_REGION |
AWS region (e.g. us-east-1) |
AWS_ACCESS_KEY_ID |
AWS access key |
AWS_SECRET_ACCESS_KEY |
AWS secret key |
AWS_ENDPOINT_URL |
Custom S3-compatible endpoint (e.g. http://minio:9000) |
Set TRUSS_STORAGE_BACKEND=gcs and configure:
| Variable | Description |
|---|---|
TRUSS_GCS_BUCKET |
Default GCS bucket name (required) |
TRUSS_GCS_ENDPOINT |
Custom endpoint (e.g. http://fake-gcs:4443) |
GOOGLE_APPLICATION_CREDENTIALS |
Path to service account JSON key file |
GOOGLE_APPLICATION_CREDENTIALS_JSON |
Inline service account JSON (alternative to file path) |
Set TRUSS_STORAGE_BACKEND=azure and configure:
| Variable | Description |
|---|---|
TRUSS_AZURE_CONTAINER |
Default container name (required) |
TRUSS_AZURE_ENDPOINT |
Custom endpoint (e.g. http://azurite:10000/devstoreaccount1) |
AZURE_STORAGE_ACCOUNT_NAME |
Storage account name (3-24 lowercase alphanumeric) |
By default, truss uses anonymous access, which works for public containers and Azurite local development. For private containers, append a SAS token to TRUSS_AZURE_ENDPOINT. On Azure-hosted compute (App Service, AKS, VMs), managed identity is used automatically when no explicit credentials are provided.
In production, place a CDN such as CloudFront (or a reverse proxy like nginx / Envoy) in front of truss so that transformed images are cached at the edge. See the API Reference for detailed CDN configuration guidance, including cache key setup and public vs. private endpoint visibility.
truss supports graceful shutdown for zero-downtime deployments. The TRUSS_SHUTDOWN_DRAIN_SECS variable controls the drain period (default: 10 seconds). During this period the server keeps accepting and answering requests, and /health/ready returns 503 to every probe so that load balancers stop sending new traffic while in-flight requests complete. The listener is closed as soon as the drain period ends, before in-flight requests are given their remaining time, so a connection attempted after it is refused rather than left waiting.
On Kubernetes, set terminationGracePeriodSeconds >= drain + 20 (e.g. 35 for the default 10 s drain).
The drain is started by SIGTERM or SIGINT on Unix. On Windows it is started by a console control event, which is what the operating system delivers in place of the signals it does not raise: Ctrl+C, Ctrl+Break, the console window being closed, the user logging off, and the system shutting down. Windows still never raises SIGTERM, so nothing depends on it. The last three of those five are terminating events, where the operating system kills the process as soon as the handler returns and allows only a few seconds before it stops asking — about five, set by the HungAppTimeout and WaitToKillServiceTimeout registry values — so truss holds the process open for up to four seconds waiting for the drain and the drain there is best effort. Ctrl+C and Ctrl+Break are not terminating, so the full TRUSS_SHUTDOWN_DRAIN_SECS window applies to them as it does on Unix. The published container image is Linux.
Per-client rate limiting is off by default. Set TRUSS_RATE_LIMIT_RPS to a positive value to enable it; each client IP then gets a token bucket refilling at that rate, with a capacity of TRUSS_RATE_LIMIT_BURST (defaulting to the same value), and requests that find an empty bucket receive 429.
Behind a CDN or reverse proxy every connection arrives from the proxy, so without further configuration all traffic shares one bucket and the limit applies to the whole site at once rather than per client. Set TRUSS_TRUSTED_PROXIES to the proxy addresses or CIDR ranges to fix this: when a connection comes from one of them, the client IP is taken from X-Forwarded-For (rightmost entry that is not itself a trusted proxy) or X-Real-IP. Only list addresses you control, because trusting an address means trusting whatever it puts in those headers.
The limit applies to the image routes -- /images/by-path, /images/by-url, /images:transform and /images -- and to a path truss does not serve. /health, /health/live, /health/ready and /metrics are outside it: a liveness probe answered 429 is a failed probe, and an orchestrator that fails enough of them restarts the process, which is the opposite of what shedding load is for. Use TRUSS_METRICS_TOKEN and TRUSS_HEALTH_TOKEN to control access to those endpoints.
| Endpoint | Purpose |
|---|---|
GET, HEAD /health/live |
Liveness probe (always returns 200) |
GET, HEAD /health/ready |
Readiness probe (returns 503 when draining, when the storage or cache root is unreachable, when the cache disk is below its minimum free bytes, or when RSS is over its limit). Transform capacity is reported in the transformCapacity check but does not withdraw readiness: a server with every slot busy is answering what it accepted, and a request that finds no free slot is shed on its own with 503 and a Retry-After |
Configure health thresholds with:
TRUSS_HEALTH_CACHE_MIN_FREE_BYTES-- minimum free bytes on cache diskTRUSS_HEALTH_MAX_MEMORY_BYTES-- maximum process RSS (Linux only)