Deployment
Docker
imgx ships as a multi-arch Docker image (linux/amd64, linux/arm64) built on Alpine Linux.
Pull from GHCR
docker pull ghcr.io/officialunofficial/imgx:latestHTTP origin
docker run -p 8080:8080 \
-e IMGX_ORIGIN_TYPE=http \
-e IMGX_ORIGIN_BASE_URL=https://images.example.com \
ghcr.io/officialunofficial/imgx:latestR2 origin
docker run -p 8080:8080 \
-e IMGX_ORIGIN_TYPE=r2 \
-e IMGX_R2_ENDPOINT=https://<account_id>.r2.cloudflarestorage.com \
-e IMGX_R2_ACCESS_KEY_ID=your-access-key \
-e IMGX_R2_SECRET_ACCESS_KEY=your-secret-key \
-e IMGX_R2_BUCKET_ORIGINALS=originals \
-e IMGX_R2_BUCKET_VARIANTS=variants \
ghcr.io/officialunofficial/imgx:latestEnvironment file
docker run -p 8080:8080 --env-file .env ghcr.io/officialunofficial/imgx:latestBuild locally
docker build -t imgx .
docker run -p 8080:8080 -e IMGX_ORIGIN_BASE_URL=https://images.example.com imgxThe Dockerfile uses a two-stage build:
- Build stage —
rust:alpinewith vips-dev,cargo build --release - Runtime stage — Alpine with only the vips runtime library
Docker Compose
services:
imgx:
image: ghcr.io/officialunofficial/imgx:latest
ports:
- "8080:8080"
environment:
IMGX_ORIGIN_TYPE: http
IMGX_ORIGIN_BASE_URL: https://images.example.com
IMGX_CACHE_ENABLED: "true"
IMGX_CACHE_MAX_SIZE_BYTES: "536870912"
IMGX_SERVER_PORT: "8080"
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 5s
restart: unless-stoppedBuild from source
Requirements:
- Rust (stable)
- libvips 8.14.0 or later (with development headers)
macOS
brew install vips
cargo build --release -p imgx
./target/release/imgxAlpine Linux
apk add vips-dev musl-dev pkgconfig
cargo build --release -p imgx
./target/release/imgxHealth checks and probes
imgx exposes three endpoints for monitoring.
/health
Returns 200 with {"status":"ok"} when the server is running. Use this for Docker HEALTHCHECK, load balancer health checks, and uptime monitors.
curl http://localhost:8080/health
# {"status":"ok"}/ready
Returns 200 with {"ready":true} when the server is ready to accept requests. Use this for Kubernetes readiness probes.
curl http://localhost:8080/ready
# {"ready":true}/metrics
Returns 200 with text/plain; version=0.0.4 — standard Prometheus exposition format, scrapeable directly by Prometheus, Grafana Agent, the Datadog agent's OpenMetrics check, or any compatible collector:
# HELP imgx_requests_total Total number of HTTP requests handled.
# TYPE imgx_requests_total counter
imgx_requests_total 1042
# HELP imgx_cache_hits_total Total number of image-transform cache hits.
# TYPE imgx_cache_hits_total counter
imgx_cache_hits_total 891
# HELP imgx_cache_misses_total Total number of image-transform cache misses.
# TYPE imgx_cache_misses_total counter
imgx_cache_misses_total 151
# HELP imgx_cache_entries Current number of entries in the cache (0 for backends that don't track this).
# TYPE imgx_cache_entries gauge
imgx_cache_entries 148
# HELP imgx_uptime_seconds Seconds since the server started.
# TYPE imgx_uptime_seconds gauge
imgx_uptime_seconds 3600| Metric | Type | Description |
|---|---|---|
imgx_requests_total | counter | Total HTTP requests served since startup |
imgx_cache_hits_total | counter | Requests served from cache |
imgx_cache_misses_total | counter | Requests that required an origin fetch |
imgx_cache_entries | gauge | Current entries in the L1 memory cache (0 for the R2/Noop backends, which don't track this) |
imgx_uptime_seconds | gauge | Seconds since server startup |
Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: imgx
spec:
replicas: 2
selector:
matchLabels:
app: imgx
template:
metadata:
labels:
app: imgx
spec:
containers:
- name: imgx
image: ghcr.io/officialunofficial/imgx:latest
ports:
- containerPort: 8080
env:
- name: IMGX_ORIGIN_TYPE
value: "http"
- name: IMGX_ORIGIN_BASE_URL
value: "https://images.example.com"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 3
periodSeconds: 5
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"CDN
imgx is designed to sit behind a CDN. Image responses include:
Cache-Control: public, max-age=<ttl>— controlled byIMGX_CACHE_DEFAULT_TTL_SECONDSETag— content-based hash for conditional requests (304 Not Modified)Vary: Accept— tells the CDN to cache separate variants per format negotiation
Configure your CDN to forward the Accept header and respect Vary: Accept for correct content negotiation.