Docker
The images on GHCR (ghcr.io/oximg/oximg) and Docker Hub
(docker.io/oximg/oximg) are multi-arch (linux/amd64 + linux/arm64),
include AVIF, run as an unprivileged user (uid 10001), and carry a
built-in HEALTHCHECK against /health.
Pin a version
Section titled “Pin a version”latest rebuilds on every push to main — it is a moving target
suitable for trying oximg out, not for production. Tagged releases
publish immutable version tags; pin one (or a digest):
docker pull ghcr.io/oximg/oximg:0.8.2 # version tagdocker pull ghcr.io/oximg/oximg@sha256:... # or stronger: a digestLocal images directory
Section titled “Local images directory”docker run -d --name oximg \ -p 8081:8081 \ -v /srv/images:/images:ro \ ghcr.io/oximg/oximg:0.8.2curl "localhost:8081/resize/500/500/photo.jpg" -o out.jpgMount the source directory read-only: the server never writes to it,
and a ro mount makes that a guarantee instead of a convention.
Remote origin instead of a volume
Section titled “Remote origin instead of a volume”Set OXIMG_SOURCE_BASE_URL and sources are fetched from
<base>/<file> over HTTP(S) (rustls; redirects are refused by design —
point the base directly at the right host). <file> may span
directories, so an existing bucket or CDN layout
(/resize/640/480/albums/2026/photo.jpg) is addressable as-is:
docker run -d --name oximg -p 8081:8081 \ -e OXIMG_SOURCE_BASE_URL=https://static.example.com/originals \ ghcr.io/oximg/oximg:0.8.2The fetcher sends no credentials, so the origin must be reachable without authentication (public bucket, internal service, or a URL that embeds its own auth).
docker-compose
Section titled “docker-compose”services: oximg: image: ghcr.io/oximg/oximg:0.8.2 ports: - "8081:8081" volumes: - /srv/images:/images:ro environment: QUALITY: "80" OXIMG_MAX_SRC_PIXELS: "30000000" # tighten in memory-constrained deploys restart: unless-stoppedAll configuration is environment variables — see the README’s
environment-variable list for the full knob inventory (quality,
formats, limits, URL signing, Accept negotiation).
Stopping and upgrading
Section titled “Stopping and upgrading”docker stop sends SIGTERM; oximg stops accepting connections,
finishes in-flight requests, and exits 0. Docker escalates to SIGKILL
after -t seconds (default 10) — leave that at 10s or higher so slow
encodes (AVIF especially) can drain:
docker stop -t 15 oximgBuilding your own image
Section titled “Building your own image”The repo’s Dockerfile needs no host dependencies (it compiles a
pinned SVT-AV1 internally) and accepts codegen tuning for
single-machine deploys:
docker build -t oximg --build-arg RUSTFLAGS="-C target-cpu=native" .Operational notes
Section titled “Operational notes”- Logging: failures always log one structured line to stderr;
OXIMG_LOG=requestalso logs successes. There is no log file — collect the container’s stderr. - Caching: every 200 carries
Cache-Control: public, max-age=31536000. Put a CDN or caching proxy in front; oximg itself does not cache results (concurrent identical requests are coalesced instead). If you enableOXIMG_AUTO_FORMAT, make sure the cache honorsVary: Accept— see the README. - Memory: per-request decode memory is bounded by
OXIMG_MAX_SRC_PIXELS(default 64,000,000 px) and concurrency is pinned to the core count. On small instances, lowering the pixel cap is the effective memory lever.