Image CDN — Cloudinary, imgproxy

Image CDN — специализированный CDN для изображений, который на лету выполняет ресайзинг, конвертацию формата (WebP/AVIF), оптимизацию качества и кеширование по параметрам URL, избавляя от необходимости хранить множество вариантов изображений.

Зачем нужно

Без Image CDN нужно заранее создавать и хранить десятки вариантов каждого изображения (thumbnail, webp, avif, @2x). Image CDN делает это динамически через URL-параметры и кеширует результат на edge. Значительно упрощает responsive images и ускоряет LCP.

Где используется

  • E-commerce: тысячи товарных изображений в разных размерах
  • CMS и блог-платформы: пользовательские загрузки
  • Social: аватары, cover-фото в разных размерах

Основной контент

Cloudinary: URL-параметры трансформации

https://res.cloudinary.com/{cloud_name}/image/upload/{transformations}/{public_id}

# Базовые трансформации:
w_800,h_600,c_fill    — ресайз 800x600, crop fill
f_auto                — автовыбор формата (WebP/AVIF по Accept)
q_auto                — автооптимизация качества
fl_progressive        — прогрессивный JPEG

# Полный пример:
https://res.cloudinary.com/demo/image/upload/w_400,f_auto,q_auto/sample.jpg

Cloudinary в Next.js

// next.config.js
module.exports = {
  images: {
    remotePatterns: [{
      protocol: 'https',
      hostname: 'res.cloudinary.com',
    }],
  },
};

// components/ProductImage.jsx
import Image from 'next/image';

export function ProductImage({ publicId, alt }) {
  return (
    <Image
      src={`https://res.cloudinary.com/mycloud/image/upload/f_auto,q_auto/${publicId}`}
      alt={alt}
      width={800}
      height={600}
      sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
    />
  );
}

imgproxy — self-hosted альтернатива

# Docker запуск imgproxy
docker run -p 8080:8080 \
  -e IMGPROXY_KEY=your_key \
  -e IMGPROXY_SALT=your_salt \
  -e IMGPROXY_MAX_SRC_RESOLUTION=50 \
  darthsim/imgproxy

# URL формат imgproxy:
# /insecure/resize:fit:800:600/plain/https://origin.com/image.jpg@webp
// Генерация signed URL для imgproxy
const crypto = require('crypto');

function imgproxyUrl(originUrl, { width, height, format = 'webp' }) {
  const processing = `resize:fit:${width}:${height}`;
  const path = `/insecure/${processing}/plain/${originUrl}@${format}`;

  const hmac = crypto
    .createHmac('sha256', Buffer.from(process.env.IMGPROXY_KEY, 'hex'))
    .update(Buffer.from(process.env.IMGPROXY_SALT, 'hex'))
    .update(path)
    .digest('base64url');

  return `https://images.example.com/${hmac}${path}`;
}

const url = imgproxyUrl('https://storage.example.com/product.jpg', {
  width: 400, height: 300, format: 'avif',
});

srcset для responsive images

<!-- С Image CDN автоматически генерируем нужные размеры -->
<img
  src="https://cdn.example.com/w_800/photo.jpg"
  srcset="
    https://cdn.example.com/w_400/photo.jpg 400w,
    https://cdn.example.com/w_800/photo.jpg 800w,
    https://cdn.example.com/w_1200/photo.jpg 1200w
  "
  sizes="(max-width: 640px) 100vw, 800px"
  alt="Photo"
  loading="lazy"
  decoding="async"
>

Частые ошибки

  • Хранение оригинальных 5MB фото на сервере без трансформации — отдача огромных изображений
  • Отсутствие sizes атрибута при srcset — браузер загружает неподходящий размер
  • Трансформация при каждом запросе без кеша — Image CDN ценен именно кешированием
  • Подписи URL без валидации origin — открывает SSRF через Image CDN

Связанные темы

Ресурсы