Deployment Guide
Manael is distributed as a stateless Docker container, making it straightforward to deploy to modern container orchestration platforms. This guide covers common deployment scenarios.
Docker Compose
The following docker-compose.yml shows how to run Manael alongside a local image server:
services:
manael:
image: ghcr.io/manaelproxy/manael:v2.1.0
ports:
- "8080:8080"
environment:
- MANAEL_UPSTREAM_URL=http://origin:9000
- MANAEL_ENABLE_AVIF=true
depends_on:
- origin
origin:
image: nginx:alpine
volumes:
- ./images:/usr/share/nginx/html:ro
Start the stack with:
docker compose up
Manael listens on port 8080 and forwards image requests to the origin service. Set MANAEL_ENABLE_AVIF=true to enable AVIF conversion in addition to the default WebP conversion.
Google Cloud Run
Cloud Run is a good fit for Manael because it scales to zero and handles traffic spikes automatically. Since AVIF conversion is CPU-intensive, allocate at least 1 GiB of memory to avoid out-of-memory errors.
Deploy Manael to Cloud Run with the gcloud CLI:
gcloud run deploy manael \
--image ghcr.io/manaelproxy/manael:v2.1.0 \
--region us-central1 \
--platform managed \
--allow-unauthenticated \
--set-env-vars MANAEL_UPSTREAM_URL=https://storage.example.com,MANAEL_ENABLE_AVIF=true \
--memory 1Gi \
--cpu 1
| Flag | Description |
|---|---|
--image |
The Manael container image from GHCR. |
--set-env-vars |
Comma-separated KEY=VALUE pairs for environment variables. |
--memory |
Memory allocated per container instance. Increase to 2Gi if you experience OOM kills with AVIF. |
--cpu |
Number of vCPUs per container instance. |
--allow-unauthenticated |
Allows public access. Remove this flag if you want to restrict access. |
After deployment, Cloud Run prints the service URL. Place a CDN or Cloud CDN in front of that URL to cache the converted images.
Kubernetes
The following manifests deploy Manael as a Deployment with a Service that exposes it inside the cluster. Apply resource requests and limits to prevent OOM kills, especially when AVIF conversion is enabled.
Deployment and Service
Save the following manifest to a file named manael.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: manael
labels:
app: manael
spec:
replicas: 2
selector:
matchLabels:
app: manael
template:
metadata:
labels:
app: manael
spec:
containers:
- name: manael
image: ghcr.io/manaelproxy/manael:v2.1.0
ports:
- containerPort: 8080
env:
- name: MANAEL_UPSTREAM_URL
value: "https://storage.example.com"
- name: MANAEL_ENABLE_AVIF
value: "true"
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1000m"
memory: "1Gi"
---
apiVersion: v1
kind: Service
metadata:
name: manael
spec:
selector:
app: manael
ports:
- protocol: TCP
port: 80
targetPort: 8080
Apply the manifest with:
kubectl apply -f manael.yaml
Resource guidance
| Workload | Memory request | Memory limit | Notes |
|---|---|---|---|
| WebP only (default) | 128Mi |
512Mi |
Suitable for low-to-medium traffic. |
| WebP + AVIF | 256Mi |
1Gi |
AVIF encoding is more CPU- and memory-intensive. |
| High traffic | 512Mi |
2Gi |
Scale replicas horizontally instead of increasing limits further. |
Manael is stateless, so horizontal scaling (increasing replicas) is the preferred way to handle additional load. No shared storage or session affinity is required.