Skip to content
LogoLogo

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:latest

HTTP origin

docker run -p 8080:8080 \
  -e IMGX_ORIGIN_TYPE=http \
  -e IMGX_ORIGIN_BASE_URL=https://images.example.com \
  ghcr.io/officialunofficial/imgx:latest

R2 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:latest

Environment file

docker run -p 8080:8080 --env-file .env ghcr.io/officialunofficial/imgx:latest

Build locally

docker build -t imgx .
docker run -p 8080:8080 -e IMGX_ORIGIN_BASE_URL=https://images.example.com imgx

The Dockerfile uses a two-stage build:

  1. Build stagerust:alpine with vips-dev, cargo build --release
  2. 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-stopped

Build 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/imgx

Alpine Linux

apk add vips-dev musl-dev pkgconfig
cargo build --release -p imgx
./target/release/imgx

Health 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
MetricTypeDescription
imgx_requests_totalcounterTotal HTTP requests served since startup
imgx_cache_hits_totalcounterRequests served from cache
imgx_cache_misses_totalcounterRequests that required an origin fetch
imgx_cache_entriesgaugeCurrent entries in the L1 memory cache (0 for the R2/Noop backends, which don't track this)
imgx_uptime_secondsgaugeSeconds 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 by IMGX_CACHE_DEFAULT_TTL_SECONDS
  • ETag — 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.