From 4b2bc71f956124ed5812eddaefbe823748a6c596 Mon Sep 17 00:00:00 2001 From: Vladyslav Prosolupov Date: Thu, 5 Mar 2026 08:16:54 +0100 Subject: [PATCH] feat: Add imgproxy template (#714) * feat: Add imgproxy template * fix: Configure docker-compose to match requirements * fix: Process meta * fix: Change logo name * fix: Remove incorrect mounts * fix: Expose 80 port instead of direct mapping * fix: Change nginx cache keys default zone size and correct format negotiation * fix: Escaping --- blueprints/imgproxy/docker-compose.yml | 76 +++++++++++++++++++++++++ blueprints/imgproxy/imgproxy.png | Bin 0 -> 4603 bytes blueprints/imgproxy/template.toml | 56 ++++++++++++++++++ meta.json | 55 ++++++++++++------ 4 files changed, 169 insertions(+), 18 deletions(-) create mode 100644 blueprints/imgproxy/docker-compose.yml create mode 100644 blueprints/imgproxy/imgproxy.png create mode 100644 blueprints/imgproxy/template.toml diff --git a/blueprints/imgproxy/docker-compose.yml b/blueprints/imgproxy/docker-compose.yml new file mode 100644 index 00000000..e9bc86a1 --- /dev/null +++ b/blueprints/imgproxy/docker-compose.yml @@ -0,0 +1,76 @@ +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 < /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: diff --git a/blueprints/imgproxy/imgproxy.png b/blueprints/imgproxy/imgproxy.png new file mode 100644 index 0000000000000000000000000000000000000000..cb26b97bb4ae4bdd5ee2bac9527fc2ed6301e470 GIT binary patch literal 4603 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