Dokploy

imgproxy

imgproxy is a fast and secure image processing server, fronted by nginx with built-in response caching for repeated transformations.

imgproxy logo

Configuration

version: "3.8"
services:
  imgproxy:
    image: darthsim/imgproxy:v3.30.1
    restart: unless-stopped
    environment:
      IMGPROXY_KEY: ${IMGPROXY_KEY}
      IMGPROXY_SALT: ${IMGPROXY_SALT}
      IMGPROXY_ENABLE_WEBP_DETECTION: ${IMGPROXY_ENABLE_WEBP_DETECTION:-true}
      IMGPROXY_ENFORCE_WEBP: ${IMGPROXY_ENFORCE_WEBP:-true}
      IMGPROXY_TTL: ${IMGPROXY_TTL:-30600}
      IMGPROXY_DEVELOPMENT_ERRORS_MODE: ${IMGPROXY_DEVELOPMENT_ERRORS_MODE:-false}
      IMGPROXY_READ_TIMEOUT: ${IMGPROXY_READ_TIMEOUT:-10}
      IMGPROXY_WRITE_TIMEOUT: ${IMGPROXY_WRITE_TIMEOUT:-10}
      IMGPROXY_KEEP_ALIVE_TIMEOUT: ${IMGPROXY_KEEP_ALIVE_TIMEOUT:-10}
      IMGPROXY_DOWNLOAD_TIMEOUT: ${IMGPROXY_DOWNLOAD_TIMEOUT:-5}
      IMGPROXY_CONCURRENCY: ${IMGPROXY_CONCURRENCY:-}
      IMGPROXY_MAX_CLIENTS: ${IMGPROXY_MAX_CLIENTS:-10}
      IMGPROXY_SO_REUSEPORT: ${IMGPROXY_SO_REUSEPORT:-}
      IMGPROXY_USER_AGENT: ${IMGPROXY_USER_AGENT:-}
      IMGPROXY_USE_ETAG: ${IMGPROXY_USE_ETAG:-true}
      IMGPROXY_QUALITY: ${IMGPROXY_QUALITY:-80}
      IMGPROXY_ALLOWED_SOURCES: ${IMGPROXY_ALLOWED_SOURCES}
      IMGPROXY_ALLOW_ORIGIN: ${IMGPROXY_ALLOW_ORIGIN:-*}
      IMGPROXY_MAX_SRC_FILE_SIZE: ${IMGPROXY_MAX_SRC_FILE_SIZE:-20971520}
      IMGPROXY_MAX_SRC_RESOLUTION: ${IMGPROXY_MAX_SRC_RESOLUTION:-50}
      IMGPROXY_LOG_LEVEL: ${IMGPROXY_LOG_LEVEL:-error}

  nginx:
    image: nginx:1.28.2-alpine
    restart: unless-stopped
    expose:
      - 80
    environment:
      NGINX_CACHE_LEVELS: ${NGINX_CACHE_LEVELS:-1:2}
      NGINX_CACHE_KEYS_ZONE_SIZE: ${NGINX_CACHE_KEYS_ZONE_SIZE:-32m}
      NGINX_CACHE_MAX_SIZE: ${NGINX_CACHE_MAX_SIZE:-500m}
      NGINX_CACHE_INACTIVE: ${NGINX_CACHE_INACTIVE:-30d}
      NGINX_CACHE_USE_TEMP_PATH: ${NGINX_CACHE_USE_TEMP_PATH:-off}
      NGINX_CACHE_EXPIRES: ${NGINX_CACHE_EXPIRES:-30d}
    depends_on:
      - imgproxy
    volumes:
      - nginx-cache:/tmp/cache
    command:
      - /bin/sh
      - -c
      - |
        cat <<EOF > /etc/nginx/conf.d/default.conf
        proxy_cache_path /tmp/cache levels=$${NGINX_CACHE_LEVELS} keys_zone=my_cache:$${NGINX_CACHE_KEYS_ZONE_SIZE} max_size=$${NGINX_CACHE_MAX_SIZE} inactive=$${NGINX_CACHE_INACTIVE} use_temp_path=$${NGINX_CACHE_USE_TEMP_PATH};

        server {
          listen 80 default_server;
          listen [::]:80 default_server;

          location / {
            expires $${NGINX_CACHE_EXPIRES};
            access_log off;
            set \$$handle_webp 0;
            if (\$$http_accept ~* "image/webp") {
              set \$$handle_webp 1;
            }
            proxy_cache my_cache;
            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
            proxy_cache_background_update on;
            proxy_cache_lock on;
            proxy_cache_key "\$$scheme\$$host\$$uri\$$handle_webp";
            server_tokens off;
            proxy_pass http://imgproxy:8080;
          }
        }
        EOF
        exec nginx -g 'daemon off;'

volumes:
  nginx-cache:
[variables]
main_domain = "${domain}"
imgproxy_key = "${hash:128}"
imgproxy_salt = "${hash:128}"
imgproxy_allowed_sources = "http://${main_domain},https://${main_domain}"
imgproxy_quality = "80"
imgproxy_ttl = "30600"
imgproxy_max_src_file_size = "20971520"
imgproxy_max_src_resolution = "50"
imgproxy_log_level = "error"
imgproxy_max_clients = "10"
imgproxy_allow_origin = "*"
imgproxy_enable_webp_detection = "true"
imgproxy_enforce_webp = "true"
imgproxy_use_etag = "true"
nginx_cache_levels = "1:2"
nginx_cache_keys_zone_size = "32m"
nginx_cache_max_size = "500m"
nginx_cache_inactive = "30d"
nginx_cache_use_temp_path = "off"
nginx_cache_expires = "30d"

[config]
[[config.domains]]
serviceName = "nginx"
port = 80
host = "${main_domain}"

[config.env]
IMGPROXY_KEY = "${imgproxy_key}"
IMGPROXY_SALT = "${imgproxy_salt}"
IMGPROXY_ENABLE_WEBP_DETECTION = "${imgproxy_enable_webp_detection}"
IMGPROXY_ENFORCE_WEBP = "${imgproxy_enforce_webp}"
IMGPROXY_TTL = "${imgproxy_ttl}"
IMGPROXY_DEVELOPMENT_ERRORS_MODE = "false"
IMGPROXY_READ_TIMEOUT = "10"
IMGPROXY_WRITE_TIMEOUT = "10"
IMGPROXY_KEEP_ALIVE_TIMEOUT = "10"
IMGPROXY_DOWNLOAD_TIMEOUT = "5"
IMGPROXY_CONCURRENCY = ""
IMGPROXY_MAX_CLIENTS = "${imgproxy_max_clients}"
IMGPROXY_SO_REUSEPORT = ""
IMGPROXY_USER_AGENT = ""
IMGPROXY_USE_ETAG = "${imgproxy_use_etag}"
IMGPROXY_QUALITY = "${imgproxy_quality}"
IMGPROXY_ALLOWED_SOURCES = "${imgproxy_allowed_sources}"
IMGPROXY_ALLOW_ORIGIN = "${imgproxy_allow_origin}"
IMGPROXY_MAX_SRC_FILE_SIZE = "${imgproxy_max_src_file_size}"
IMGPROXY_MAX_SRC_RESOLUTION = "${imgproxy_max_src_resolution}"
IMGPROXY_LOG_LEVEL = "${imgproxy_log_level}"
NGINX_CACHE_LEVELS = "${nginx_cache_levels}"
NGINX_CACHE_KEYS_ZONE_SIZE = "${nginx_cache_keys_zone_size}"
NGINX_CACHE_MAX_SIZE = "${nginx_cache_max_size}"
NGINX_CACHE_INACTIVE = "${nginx_cache_inactive}"
NGINX_CACHE_USE_TEMP_PATH = "${nginx_cache_use_temp_path}"
NGINX_CACHE_EXPIRES = "${nginx_cache_expires}"

Base64

To import this template in Dokploy: create a Compose service → AdvancedBase64 import and paste the content below:

ewogICJjb21wb3NlIjogInZlcnNpb246IFwiMy44XCJcbnNlcnZpY2VzOlxuICBpbWdwcm94eTpcbiAgICBpbWFnZTogZGFydGhzaW0vaW1ncHJveHk6djMuMzAuMVxuICAgIHJlc3RhcnQ6IHVubGVzcy1zdG9wcGVkXG4gICAgZW52aXJvbm1lbnQ6XG4gICAgICBJTUdQUk9YWV9LRVk6ICR7SU1HUFJPWFlfS0VZfVxuICAgICAgSU1HUFJPWFlfU0FMVDogJHtJTUdQUk9YWV9TQUxUfVxuICAgICAgSU1HUFJPWFlfRU5BQkxFX1dFQlBfREVURUNUSU9OOiAke0lNR1BST1hZX0VOQUJMRV9XRUJQX0RFVEVDVElPTjotdHJ1ZX1cbiAgICAgIElNR1BST1hZX0VORk9SQ0VfV0VCUDogJHtJTUdQUk9YWV9FTkZPUkNFX1dFQlA6LXRydWV9XG4gICAgICBJTUdQUk9YWV9UVEw6ICR7SU1HUFJPWFlfVFRMOi0zMDYwMH1cbiAgICAgIElNR1BST1hZX0RFVkVMT1BNRU5UX0VSUk9SU19NT0RFOiAke0lNR1BST1hZX0RFVkVMT1BNRU5UX0VSUk9SU19NT0RFOi1mYWxzZX1cbiAgICAgIElNR1BST1hZX1JFQURfVElNRU9VVDogJHtJTUdQUk9YWV9SRUFEX1RJTUVPVVQ6LTEwfVxuICAgICAgSU1HUFJPWFlfV1JJVEVfVElNRU9VVDogJHtJTUdQUk9YWV9XUklURV9USU1FT1VUOi0xMH1cbiAgICAgIElNR1BST1hZX0tFRVBfQUxJVkVfVElNRU9VVDogJHtJTUdQUk9YWV9LRUVQX0FMSVZFX1RJTUVPVVQ6LTEwfVxuICAgICAgSU1HUFJPWFlfRE9XTkxPQURfVElNRU9VVDogJHtJTUdQUk9YWV9ET1dOTE9BRF9USU1FT1VUOi01fVxuICAgICAgSU1HUFJPWFlfQ09OQ1VSUkVOQ1k6ICR7SU1HUFJPWFlfQ09OQ1VSUkVOQ1k6LX1cbiAgICAgIElNR1BST1hZX01BWF9DTElFTlRTOiAke0lNR1BST1hZX01BWF9DTElFTlRTOi0xMH1cbiAgICAgIElNR1BST1hZX1NPX1JFVVNFUE9SVDogJHtJTUdQUk9YWV9TT19SRVVTRVBPUlQ6LX1cbiAgICAgIElNR1BST1hZX1VTRVJfQUdFTlQ6ICR7SU1HUFJPWFlfVVNFUl9BR0VOVDotfVxuICAgICAgSU1HUFJPWFlfVVNFX0VUQUc6ICR7SU1HUFJPWFlfVVNFX0VUQUc6LXRydWV9XG4gICAgICBJTUdQUk9YWV9RVUFMSVRZOiAke0lNR1BST1hZX1FVQUxJVFk6LTgwfVxuICAgICAgSU1HUFJPWFlfQUxMT1dFRF9TT1VSQ0VTOiAke0lNR1BST1hZX0FMTE9XRURfU09VUkNFU31cbiAgICAgIElNR1BST1hZX0FMTE9XX09SSUdJTjogJHtJTUdQUk9YWV9BTExPV19PUklHSU46LSp9XG4gICAgICBJTUdQUk9YWV9NQVhfU1JDX0ZJTEVfU0laRTogJHtJTUdQUk9YWV9NQVhfU1JDX0ZJTEVfU0laRTotMjA5NzE1MjB9XG4gICAgICBJTUdQUk9YWV9NQVhfU1JDX1JFU09MVVRJT046ICR7SU1HUFJPWFlfTUFYX1NSQ19SRVNPTFVUSU9OOi01MH1cbiAgICAgIElNR1BST1hZX0xPR19MRVZFTDogJHtJTUdQUk9YWV9MT0dfTEVWRUw6LWVycm9yfVxuXG4gIG5naW54OlxuICAgIGltYWdlOiBuZ2lueDoxLjI4LjItYWxwaW5lXG4gICAgcmVzdGFydDogdW5sZXNzLXN0b3BwZWRcbiAgICBleHBvc2U6XG4gICAgICAtIDgwXG4gICAgZW52aXJvbm1lbnQ6XG4gICAgICBOR0lOWF9DQUNIRV9MRVZFTFM6ICR7TkdJTlhfQ0FDSEVfTEVWRUxTOi0xOjJ9XG4gICAgICBOR0lOWF9DQUNIRV9LRVlTX1pPTkVfU0laRTogJHtOR0lOWF9DQUNIRV9LRVlTX1pPTkVfU0laRTotMzJtfVxuICAgICAgTkdJTlhfQ0FDSEVfTUFYX1NJWkU6ICR7TkdJTlhfQ0FDSEVfTUFYX1NJWkU6LTUwMG19XG4gICAgICBOR0lOWF9DQUNIRV9JTkFDVElWRTogJHtOR0lOWF9DQUNIRV9JTkFDVElWRTotMzBkfVxuICAgICAgTkdJTlhfQ0FDSEVfVVNFX1RFTVBfUEFUSDogJHtOR0lOWF9DQUNIRV9VU0VfVEVNUF9QQVRIOi1vZmZ9XG4gICAgICBOR0lOWF9DQUNIRV9FWFBJUkVTOiAke05HSU5YX0NBQ0hFX0VYUElSRVM6LTMwZH1cbiAgICBkZXBlbmRzX29uOlxuICAgICAgLSBpbWdwcm94eVxuICAgIHZvbHVtZXM6XG4gICAgICAtIG5naW54LWNhY2hlOi90bXAvY2FjaGVcbiAgICBjb21tYW5kOlxuICAgICAgLSAvYmluL3NoXG4gICAgICAtIC1jXG4gICAgICAtIHxcbiAgICAgICAgY2F0IDw8RU9GID4gL2V0Yy9uZ2lueC9jb25mLmQvZGVmYXVsdC5jb25mXG4gICAgICAgIHByb3h5X2NhY2hlX3BhdGggL3RtcC9jYWNoZSBsZXZlbHM9JCR7TkdJTlhfQ0FDSEVfTEVWRUxTfSBrZXlzX3pvbmU9bXlfY2FjaGU6JCR7TkdJTlhfQ0FDSEVfS0VZU19aT05FX1NJWkV9IG1heF9zaXplPSQke05HSU5YX0NBQ0hFX01BWF9TSVpFfSBpbmFjdGl2ZT0kJHtOR0lOWF9DQUNIRV9JTkFDVElWRX0gdXNlX3RlbXBfcGF0aD0kJHtOR0lOWF9DQUNIRV9VU0VfVEVNUF9QQVRIfTtcblxuICAgICAgICBzZXJ2ZXIge1xuICAgICAgICAgIGxpc3RlbiA4MCBkZWZhdWx0X3NlcnZlcjtcbiAgICAgICAgICBsaXN0ZW4gWzo6XTo4MCBkZWZhdWx0X3NlcnZlcjtcblxuICAgICAgICAgIGxvY2F0aW9uIC8ge1xuICAgICAgICAgICAgZXhwaXJlcyAkJHtOR0lOWF9DQUNIRV9FWFBJUkVTfTtcbiAgICAgICAgICAgIGFjY2Vzc19sb2cgb2ZmO1xuICAgICAgICAgICAgc2V0IFxcJCRoYW5kbGVfd2VicCAwO1xuICAgICAgICAgICAgaWYgKFxcJCRodHRwX2FjY2VwdCB+KiBcImltYWdlL3dlYnBcIikge1xuICAgICAgICAgICAgICBzZXQgXFwkJGhhbmRsZV93ZWJwIDE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBwcm94eV9jYWNoZSBteV9jYWNoZTtcbiAgICAgICAgICAgIHByb3h5X2NhY2hlX3VzZV9zdGFsZSBlcnJvciB0aW1lb3V0IHVwZGF0aW5nIGh0dHBfNTAwIGh0dHBfNTAyIGh0dHBfNTAzIGh0dHBfNTA0O1xuICAgICAgICAgICAgcHJveHlfY2FjaGVfYmFja2dyb3VuZF91cGRhdGUgb247XG4gICAgICAgICAgICBwcm94eV9jYWNoZV9sb2NrIG9uO1xuICAgICAgICAgICAgcHJveHlfY2FjaGVfa2V5IFwiXFwkJHNjaGVtZVxcJCRob3N0XFwkJHVyaVxcJCRoYW5kbGVfd2VicFwiO1xuICAgICAgICAgICAgc2VydmVyX3Rva2VucyBvZmY7XG4gICAgICAgICAgICBwcm94eV9wYXNzIGh0dHA6Ly9pbWdwcm94eTo4MDgwO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBFT0ZcbiAgICAgICAgZXhlYyBuZ2lueCAtZyAnZGFlbW9uIG9mZjsnXG5cbnZvbHVtZXM6XG4gIG5naW54LWNhY2hlOlxuIiwKICAiY29uZmlnIjogIlt2YXJpYWJsZXNdXG5tYWluX2RvbWFpbiA9IFwiJHtkb21haW59XCJcbmltZ3Byb3h5X2tleSA9IFwiJHtoYXNoOjEyOH1cIlxuaW1ncHJveHlfc2FsdCA9IFwiJHtoYXNoOjEyOH1cIlxuaW1ncHJveHlfYWxsb3dlZF9zb3VyY2VzID0gXCJodHRwOi8vJHttYWluX2RvbWFpbn0saHR0cHM6Ly8ke21haW5fZG9tYWlufVwiXG5pbWdwcm94eV9xdWFsaXR5ID0gXCI4MFwiXG5pbWdwcm94eV90dGwgPSBcIjMwNjAwXCJcbmltZ3Byb3h5X21heF9zcmNfZmlsZV9zaXplID0gXCIyMDk3MTUyMFwiXG5pbWdwcm94eV9tYXhfc3JjX3Jlc29sdXRpb24gPSBcIjUwXCJcbmltZ3Byb3h5X2xvZ19sZXZlbCA9IFwiZXJyb3JcIlxuaW1ncHJveHlfbWF4X2NsaWVudHMgPSBcIjEwXCJcbmltZ3Byb3h5X2FsbG93X29yaWdpbiA9IFwiKlwiXG5pbWdwcm94eV9lbmFibGVfd2VicF9kZXRlY3Rpb24gPSBcInRydWVcIlxuaW1ncHJveHlfZW5mb3JjZV93ZWJwID0gXCJ0cnVlXCJcbmltZ3Byb3h5X3VzZV9ldGFnID0gXCJ0cnVlXCJcbm5naW54X2NhY2hlX2xldmVscyA9IFwiMToyXCJcbm5naW54X2NhY2hlX2tleXNfem9uZV9zaXplID0gXCIzMm1cIlxubmdpbnhfY2FjaGVfbWF4X3NpemUgPSBcIjUwMG1cIlxubmdpbnhfY2FjaGVfaW5hY3RpdmUgPSBcIjMwZFwiXG5uZ2lueF9jYWNoZV91c2VfdGVtcF9wYXRoID0gXCJvZmZcIlxubmdpbnhfY2FjaGVfZXhwaXJlcyA9IFwiMzBkXCJcblxuW2NvbmZpZ11cbltbY29uZmlnLmRvbWFpbnNdXVxuc2VydmljZU5hbWUgPSBcIm5naW54XCJcbnBvcnQgPSA4MFxuaG9zdCA9IFwiJHttYWluX2RvbWFpbn1cIlxuXG5bY29uZmlnLmVudl1cbklNR1BST1hZX0tFWSA9IFwiJHtpbWdwcm94eV9rZXl9XCJcbklNR1BST1hZX1NBTFQgPSBcIiR7aW1ncHJveHlfc2FsdH1cIlxuSU1HUFJPWFlfRU5BQkxFX1dFQlBfREVURUNUSU9OID0gXCIke2ltZ3Byb3h5X2VuYWJsZV93ZWJwX2RldGVjdGlvbn1cIlxuSU1HUFJPWFlfRU5GT1JDRV9XRUJQID0gXCIke2ltZ3Byb3h5X2VuZm9yY2Vfd2VicH1cIlxuSU1HUFJPWFlfVFRMID0gXCIke2ltZ3Byb3h5X3R0bH1cIlxuSU1HUFJPWFlfREVWRUxPUE1FTlRfRVJST1JTX01PREUgPSBcImZhbHNlXCJcbklNR1BST1hZX1JFQURfVElNRU9VVCA9IFwiMTBcIlxuSU1HUFJPWFlfV1JJVEVfVElNRU9VVCA9IFwiMTBcIlxuSU1HUFJPWFlfS0VFUF9BTElWRV9USU1FT1VUID0gXCIxMFwiXG5JTUdQUk9YWV9ET1dOTE9BRF9USU1FT1VUID0gXCI1XCJcbklNR1BST1hZX0NPTkNVUlJFTkNZID0gXCJcIlxuSU1HUFJPWFlfTUFYX0NMSUVOVFMgPSBcIiR7aW1ncHJveHlfbWF4X2NsaWVudHN9XCJcbklNR1BST1hZX1NPX1JFVVNFUE9SVCA9IFwiXCJcbklNR1BST1hZX1VTRVJfQUdFTlQgPSBcIlwiXG5JTUdQUk9YWV9VU0VfRVRBRyA9IFwiJHtpbWdwcm94eV91c2VfZXRhZ31cIlxuSU1HUFJPWFlfUVVBTElUWSA9IFwiJHtpbWdwcm94eV9xdWFsaXR5fVwiXG5JTUdQUk9YWV9BTExPV0VEX1NPVVJDRVMgPSBcIiR7aW1ncHJveHlfYWxsb3dlZF9zb3VyY2VzfVwiXG5JTUdQUk9YWV9BTExPV19PUklHSU4gPSBcIiR7aW1ncHJveHlfYWxsb3dfb3JpZ2lufVwiXG5JTUdQUk9YWV9NQVhfU1JDX0ZJTEVfU0laRSA9IFwiJHtpbWdwcm94eV9tYXhfc3JjX2ZpbGVfc2l6ZX1cIlxuSU1HUFJPWFlfTUFYX1NSQ19SRVNPTFVUSU9OID0gXCIke2ltZ3Byb3h5X21heF9zcmNfcmVzb2x1dGlvbn1cIlxuSU1HUFJPWFlfTE9HX0xFVkVMID0gXCIke2ltZ3Byb3h5X2xvZ19sZXZlbH1cIlxuTkdJTlhfQ0FDSEVfTEVWRUxTID0gXCIke25naW54X2NhY2hlX2xldmVsc31cIlxuTkdJTlhfQ0FDSEVfS0VZU19aT05FX1NJWkUgPSBcIiR7bmdpbnhfY2FjaGVfa2V5c196b25lX3NpemV9XCJcbk5HSU5YX0NBQ0hFX01BWF9TSVpFID0gXCIke25naW54X2NhY2hlX21heF9zaXplfVwiXG5OR0lOWF9DQUNIRV9JTkFDVElWRSA9IFwiJHtuZ2lueF9jYWNoZV9pbmFjdGl2ZX1cIlxuTkdJTlhfQ0FDSEVfVVNFX1RFTVBfUEFUSCA9IFwiJHtuZ2lueF9jYWNoZV91c2VfdGVtcF9wYXRofVwiXG5OR0lOWF9DQUNIRV9FWFBJUkVTID0gXCIke25naW54X2NhY2hlX2V4cGlyZXN9XCJcbiIKfQ==

Tags

images, media, proxy, cdn, caching


Version: v3.30.1

On this page