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 exactly
  • location /api/assets/ matches image retrieval URLs
  • break 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 pixels
  • IMG_MAX_HEIGHT: Maximum height in pixels
  • Images maintain aspect ratio when resized

Verification

  1. Check proxy is running: docker ps | grep upload_proxy
  2. Upload a large image through your Immich app
  3. Check storage folder - image should be smaller than original
  4. 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.

Comments

  1. Markdown is allowed. HTML tags allowed: <strong>, <em>, <blockquote>, <code>, <pre>, <a>.