はじめに
ウェブサイトで画像を公開している場合、その画像のファイルサイズが大きい場合にそのサイズを縮小したり、もしくは、形式を変更してファイルサイズを縮小したいことがある。
これは、サイトの表示速度の速さや、データ流量の削減によるインフラコスト削減などが主な目的となる。
それを実現する方法として、imgproxy と呼ばれる MIT ライセンスの動画の動的変換サービスがある。
ここでは、この Docker バージョンを利用して、nginx と組み合わせることで動的に画像を縮小させる具体的な方法についてを示す。
前提となるインフラ構成
nginx + imgproxy の構成。
なお、imgproxy はキャッシュの生成機能などを持たないので、そこは nginx 側で対応する。
- サーバーの上で nginx が動作しており、外部からの HTTP/S 通信を nginx が受け取る
- imgproxy は Docker 上で動作しており、今回は 9080 ポートで内部からの通信を受け付ける
共通設定
nginx のキャッシュ設定は以下の通り、zone に imgproxy_cache という名前を設定。
proxy_cache_path /var/cache/nginx/imgproxy levels=1:2 keys_zone=imgproxy_cache:50m max_size=1g inactive=1d use_temp_path=off;
imgproxy は docker compose で以下のように稼働させている。
ここでは Docker Image は Docker Hub から取得しているが、公式リポジトリがこちら に移ったというアナウンスも書かれているので、参考にする場合は注意のこと。
今回のケースでは WordPress の uploads 以下に存在するファイルを対象に画像の動的変換を行う。
imgproxy:
image: darthsim/imgproxy:latest
container_name: imgproxy
restart: always
ports:
- "9080:8080"
environment:
- TZ=Asia/Tokyo
# imgproxy の設定
- IMGPROXY_ENABLE_LOCAL_FILES=true
- IMGPROXY_LOCAL_FILESYSTEM_ROOT=/data
- IMGPROXY_USE_ETAG=true
- IMGPROXY_CACHE_TTL=86400
- IMGPROXY_ALLOW_INSECURE_URLS=true
volumes:
- /var/www/html/wp-content/uploads:/data/uploads:ro
フォーマット変換: JPEG形式の画像をWEBP形式に変換して返す
仕様は以下の通り。
- 通常アクセス (例:
/wp-content/uploads/2025/07/image.jpg
) の場合は登録されたままの画像を返す - 末尾に
@webp
のついたアクセス (例:/wp-content/uploads/2025/07/image.jpg@webp
) の場合は画像を WebP 形式に変換して返す
この処理を行う場合、nginx には以下の location を定義する。
location ~* ^/wp-content/uploads/(.+\.(jpe?g))@webp$ {
set $img_path $1;
rewrite ^/wp-content/uploads/(.*)\.(jpe?g)@webp$ /insecure/f:jpg/plain/local:///uploads/$img_path@webp break;
proxy_pass http://localhost:9080;
proxy_cache imgproxy_cache;
proxy_cache_lock on;
proxy_cache_valid 200 7d;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
expires 7d;
add_header Cache-Control "x-maxage=604800";
add_header X-nginx-Cache $upstream_cache_status;
}
location ~* ^/wp-content/uploads/(.+\.(png))@webp$ {
set $img_path $1;
rewrite ^/wp-content/uploads/(.*)\.png@webp$ /insecure/f:png/plain/local:///uploads/$img_path@webp break;
proxy_pass http://localhost:9080;
proxy_cache imgproxy_cache;
proxy_cache_lock on;
proxy_cache_valid 200 7d;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
expires 7d;
add_header Cache-Control "x-maxage=604800";
add_header X-nginx-Cache $upstream_cache_status;
}
ポイントは以下の通り。
-
@webp
で終了する、該当ディレクトリのみの通信を受け付ける location を定義する - 内部で rewrite を行い、imgproxy の要求するパスに置き換える
- 定義した imgproxy_cache を使って、一度生成した画像は nginx レベルでキャッシュする
- nginxレベルのキャッシュが使われたか否かは x-nginx-cache のヘッダを見ればわかる
サイズの強制変換: 画像サイズを動的に小さくする
仕様は以下の通り。
- 通常アクセス (例:
/wp-content/uploads/2025/07/image.jpg
) の場合は登録されたままの画像を返す - 専用のリサイズ用 URL Prefix を用意する (今回は
/_resize/
) - リサイズ用URLにクエリ
w
のついたアクセス (例:/_resize/wp-content/uploads/2025/07/image.jpg?w=320
) の場合、画像の横幅を比率を保ったままで横サイズを動的に 320px に縮小して返す
この処理を行う場合、nginx には以下の location を定義する。
location ~* ^/_resize/wp-content/uploads/(.+\.(jpe?g|png|gif))$ {
set $img_path $1;
rewrite ^/_resize/wp-content/uploads/(.*)$ /insecure/w:$arg_w/plain/local:///uploads/$img_path break;
proxy_pass http://localhost:9080;
proxy_cache imgproxy_cache;
proxy_cache_lock on;
proxy_cache_valid 200 7d;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
expires 7d;
add_header Cache-Control "x-maxage=604800";
add_header X-nginx-Cache $upstream_cache_status;
}
ポイントは以下の通り。
- 専用の仮想 URL を用意することで、通常の場合とリサイズの場合を異なるパスで要求するようにする
- 内部で rewrite を行い、imgproxy の要求するパスに置き換える
- 定義した imgproxy_cache を使って、一度生成した画像は nginx レベルでキャッシュする
- nginxレベルのキャッシュが使われたか否かは x-nginx-cache のヘッダを見ればわかる
?w=
の数値を変えると、その都度、そのサイズに変換された画像が返される。
補足と注意点
この設定だと $arg_w
に任意の値が入ると imgproxy に負荷をかける可能性があるため、本番環境では map
を使って特定の整数値のみ許可する構成を推奨する。
map $arg_w $safe_w {
default 320;
320 320;
640 640;
1024 1024;
}
# 中略
rewrite ^/_resize/wp-content/uploads/(.*)$ /insecure/w:$safe_w/plain/local:///uploads/$img_path break;
なお、もし元画像よりも大きい数字が与えられても、元画像以上のサイズに拡大することはない。