Immich Image Compression Proxy: Save Storage Space Transparently
Immich always stores original photos/videos, which quickly fills up your disk. This guide shows how to automatically compress images during upload without modifying Immich itself.
This solution is based on the excellent work by JamesCullum. Without his innovative proxy approach, this wouldn't be possible.
How It Works
A proxy container sits between uploads and Immich server:
- Intercepts image uploads
- Resizes images to specified dimensions
- Forwards compressed images to Immich
- Completely transparent to clients
Setup
1. Add Proxy to Docker Compose
Add this service to your docker-compose.yml
:
services:
upload-proxy:
container_name: upload_proxy
image: shukebeta/multipart-upload-proxy:unified-compression
environment:
- IMG_MAX_WIDTH=1080 # Standard mobile width
- IMG_MAX_HEIGHT=3000 # Allows long screenshots
- JPEG_QUALITY=80 # JPEG compression quality (1-100, balances size and quality)
- FORWARD_DESTINATION=http://immich-server:2283/api/assets
- FILE_UPLOAD_FIELD=assetData
- LISTEN_PATH=/api/assets
ports:
- "6743:6743"
restart: always
depends_on:
- immich-server
2. Update Nginx Configuration
Critical: Simple routing doesn't work because the proxy only handles uploads, not image retrieval. Use this precise configuration:
# Only match exactly /api/assets (upload endpoint)
location = /api/assets {
# Method check: only POST goes to upload proxy
if ($request_method = POST) {
proxy_pass http://your-server:6743;
break; # Critical: prevents fallthrough
}
# Non-POST (like GET lists) go to main service
proxy_pass http://your-server:2283;
}
# /api/assets/xxxxx (with suffix - thumbnails, full images, ID access) all go to main service
location /api/assets/ {
proxy_pass http://your-server:2283;
}
# Everything else
location / {
proxy_pass http://your-server:2283;
}
Why this configuration is essential:
- Proxy only processes
multipart/form-data
uploads - GET requests for images must bypass the proxy
location = /api/assets
matches uploads exactlylocation /api/assets/
matches image retrieval URLsbreak
prevents nginx from processing additional location blocks
3. Deploy Changes
# Stop containers
docker compose down
# Start with new configuration
docker compose up -d
# Reload nginx
nginx -t && nginx -s reload
Customization
Common Size Presets
Mobile-optimized (saves ~70% space):
- IMG_MAX_WIDTH=1080
- IMG_MAX_HEIGHT=1920
Long screenshots friendly:
- IMG_MAX_WIDTH=1080
- IMG_MAX_HEIGHT=3000
Tablet-optimized:
- IMG_MAX_WIDTH=1536
- IMG_MAX_HEIGHT=2048
Custom Dimensions
Set any dimensions you want:
IMG_MAX_WIDTH
: Maximum width in pixelsIMG_MAX_HEIGHT
: Maximum height in pixels- Images maintain aspect ratio when resized
Verification
- Check proxy is running:
docker ps | grep upload_proxy
- Upload a large image through your Immich app
- Check storage folder - image should be smaller than original
- Verify image quality meets your standards
Why This Works
- Security: All authentication headers pass through untouched
- Compatibility: Uses standard HTTP - works with any client
- Transparency: Immich doesn't know compression happened
Troubleshooting
Uploads fail: Check nginx routing and proxy container logs
Images not compressed: Check nginx routing - requests may be bypassing the proxy
Poor quality: Increase IMG_MAX_WIDTH
and IMG_MAX_HEIGHT
values
Why This Proxy Approach?
Immich developers have explicitly rejected adding compression features to the core application. This proxy solution is currently the only practical way to reduce storage usage while maintaining full compatibility with all Immich clients.
Click Here to check my working configuration.