Container image
roci ships as a hardened, fully static container image: a musl-static binary on a scratch base with no shell, no libc, and no package manager. It runs as an unprivileged nonroot UID (65532), and the storage directory is the only writable path. The image is built with the full feature set (S3, LMDB, OpenTelemetry export, Prometheus /metrics, mimalloc); LDAP authentication is opt-in and not included (build with --features full,ldap).
Run
docker run -d --name roci --read-only \
-v roci-data:/var/lib/roci -p 5000:5000 \
ghcr.io/jakobmoellerdev/roci:latestMount the root filesystem read-only; only the storage volume needs to be writable. By default the container listens on 0.0.0.0:5000 and stores content in /var/lib/roci.
roci stops gracefully on SIGINT (Ctrl-C) and SIGTERM (docker stop, Kubernetes pod termination). As PID 1 in a container, the SIGTERM handler ensures connections drain and the process exits cleanly within seconds instead of waiting for the full grace period and being killed.
Besides the binary, the image holds only a CA bundle (/etc/ssl/certs/ca-certificates.crt, SSL_CERT_FILE). The S3 backend's HTTP client refuses to start without system root certificates, even for a plaintext http:// endpoint, and LDAP without ca_file trusts the system roots.
macOS
The AirPlay Receiver holds port 5000 on macOS. Publish another host port instead: -p 5001:5000.
Tags
| Tag | Meaning |
|---|---|
latest | Newest release. |
X.Y.Z / X.Y | A specific release, or the newest patch of a minor line. Pin one of these in production. |
main | Rolling build of the main branch. |
<commit-sha> | Immutable build of one commit. |
All tags are multi-arch manifests (linux/amd64, linux/arm64).
Configuration file
Passing arguments replaces the default command (--listen 0.0.0.0:5000 --storage-root /var/lib/roci). A config file must therefore set both values itself:
# roci.toml
[http]
listen = "0.0.0.0:5000"
[storage]
root = "/var/lib/roci"
[telemetry.metrics]
enabled = true # Prometheus scrape at /metricsdocker run -d --name roci --read-only \
-v roci-data:/var/lib/roci \
-v "$PWD/roci.toml:/etc/roci/roci.toml:ro" \
-p 5000:5000 \
ghcr.io/jakobmoellerdev/roci:latest --config /etc/roci/roci.tomlIn Kubernetes, mount the file from a ConfigMap and TLS keys — plus storage.metadata.hmac_key_file and an S3 secret_access_key_file, if used — from a Secret. Garbage collection, scrub quarantine (.roci-quarantine/) and metadata all stay inside the storage volume, so the read-only root filesystem is unaffected. See Configuration for every key.
Image metadata
Every published image carries the OCI pre-defined annotation keys in three places: as image-config labels (docker inspect), as annotations on each per-arch manifest, and as annotations on the multi-arch index (which GHCR uses for the package description, source link, and license).
| Key | Value |
|---|---|
created | Commit date of the built revision (UTC, RFC 3339). It is not the wall-clock build time, so rebuilding a commit gives the same value. |
version | X.Y.Z for a vX.Y.Z release tag, otherwise <cargo version>+g<short sha> |
revision | Full commit SHA |
source, url | https://github.com/jakobmoellerdev/roci |
documentation | https://jakobmoellerdev.github.io/roci/ |
authors, vendor, licenses | From [workspace.package] in Cargo.toml (licenses is an SPDX expression: Apache-2.0) |
title, description | roci, plus a one-line summary |
base.name/base.digest are omitted because the runtime stage is FROM scratch, which has no reference or digest. ref.name is omitted because the spec scopes it to index.json descriptors in an image layout. scripts/oci-meta.sh is the single source of these values for CI and just container. A release build fails if the tag does not match the Cargo.toml version.
docker buildx imagetools inspect --raw ghcr.io/jakobmoellerdev/roci:latest | jq .annotationsBuild locally
just container # build + smoke-test the running container
just container-multiarch # build the multi-arch image (linux/amd64, linux/arm64)Supply-chain provenance
Every published image has a signed build-provenance attestation, plus an embedded SBOM and SLSA provenance. Verify a pulled image with:
gh attestation verify oci://ghcr.io/jakobmoellerdev/roci:latest --owner jakobmoellerdevPlatforms
Container images are Linux-only, because OCI/Docker has no darwin runtime. The image is built on native per-arch runners, with no QEMU emulation:
- Pull requests build and smoke-test only
linux/arm64(on anubuntu-24.04-armrunner) to save time. mainandv*release tags buildlinux/amd64andlinux/arm64, assemble a multi-arch manifest, and push it to GHCR.
darwin/amd64 and darwin/arm64 binaries are attached to each GitHub release instead of being published as container platforms.