Skip to content
smallPict

Своё хранилище + CDN

Подключите собственное объектное хранилище и собственный CDN на тарифах API Velocity и Momentum: настройка для каждого провайдера, минимальные права, проверка подключения и что происходит при смене режима.

Доступно на: тарифах API Velocity и Momentum. Недоступно на Ignite (в нём нет CDN), в песочнице для разработчиков (файлы песочницы временные) и на тарифах WordPress (они используют управляемый CDN smallPict).

Кратко: в режиме BYO smallPict записывает ваши оригиналы и оптимизированные изображения в ваш бакет, а отдаёт их ваш CDN. Хранилище и CDN всегда подключаются вместе: нельзя подключить одно без другого.


Что такое BYO

На Velocity и Momentum есть два режима доставки. Режим выбирается в разделе Панель управления → CDN и хранилище.

  • Управляемый (по умолчанию): smallPict хранит ваши оригиналы в своём зашифрованном хранилище (через 90 дней они переносятся в долгосрочный архив) и отдаёт оптимизированные изображения с cdn.smallpict.app. Ничего настраивать не нужно.
  • Своё хранилище + CDN (BYO): вы подключаете S3-совместимый бакет в своём аккаунте и CDN в своём аккаунте. Каждое новое задание записывает оригинал и оптимизированный файл в ваш бакет, а API возвращает URL на домене вашего CDN.

Правило «только вместе» существует потому, что smallPict должен выполнять обе части доставки: записывать файлы и удалять устаревшие копии из кеша. Бакету без CDN некуда было бы отправлять очистку кеша; CDN без бакета было бы нечего отдавать.


Управляемый режим и BYO

Управляемый (по умолчанию)Своё хранилище + CDN
ОригиналыЗашифрованное хранилище smallPictoriginals/<job_id>/<file> в вашем бакете
Оптимизированные файлыОтдаются с cdn.smallpict.appoptimized/<job_id>.<ext> в вашем бакете, отдаются с домена вашего CDN
Квота хранилищаVelocity 50 ГБ, Momentum 100 ГБНе учитывается. Вы платите своему провайдеру хранилища.
Трафик CDNVelocity 30 ГБ/месяц, Momentum 200 ГБ/месяцНе учитывается. Вы платите своему провайдеру CDN.
ПреобразованияУчитываются в тарифеУчитываются в тарифе
Копия у smallPictДа, пока ваш аккаунт активенНет. Только временная загрузка для обработки, удаляется в течение 24 часов.
Очистка кешаАвтоматическиАвтоматически, через API вашего CDN
Производительность, домен и стоимость CDNsmallPictВы. smallPict не отвечает за производительность, домены и счета вашего CDN.

Поддерживаемые провайдеры

Хранилище (доступно сейчас): Amazon S3, Cloudflare R2, Google Cloud Storage (совместимость с S3), Alibaba Cloud OSS, Tencent Cloud COS, DigitalOcean Spaces, SumoPod Storage, MinIO и любой другой S3-совместимый сервис через собственный эндпоинт (например, Hetzner, Vultr или Wasabi).

CDN (доступно сейчас): Cloudflare и Amazon CloudFront.

Запланировано: Azure Blob Storage и другие CDN. Запросить ранний доступ можно на странице Облачные провайдеры.


Перед началом

  1. Вы на тарифе API Velocity или Momentum и вошли как администратор аккаунта.
  2. У вас есть бакет и CDN, который отдаёт файлы из этого бакета по HTTPS.
  3. Эндпоинт хранилища доступен из интернета по HTTPS. Частные, внутренние и HTTP-эндпоинты без шифрования отклоняются.
  4. Вы создали для smallPict ключи с узкими правами (см. Минимальные права ниже). Не используйте root- или админ-ключи своего аккаунта.

Затем откройте Панель управления → CDN и хранилище, выберите Своё хранилище + CDN, заполните обе части и нажмите Сохранить хранилище + CDN. smallPict выполнит проверку подключения (описана ниже) и переключит вас на BYO, только если она пройдена.


Руководства по настройке

A. Amazon S3 + Amazon CloudFront

  1. Создайте бакет в нужном регионе, например my-images в ap-southeast-1. Оставьте Block Public Access включённым.
  2. Создайте дистрибутив CloudFront с бакетом в качестве источника. Используйте Origin access control (OAC), чтобы CloudFront мог читать бакет, пока тот остаётся приватным, и примените политику бакета, которую предложит CloudFront.
  3. Необязательно: свой домен. Добавьте в дистрибутив альтернативное доменное имя (например, images.example.com) и сертификат, а затем направьте DNS-запись на дистрибутив.
  4. Создайте пользователя (или роль) IAM для хранилища с такой политикой:
JSON
{  "Version": "2012-10-17",  "Statement": [    {      "Effect": "Allow",      "Action": [        "s3:PutObject",        "s3:GetObject",        "s3:DeleteObject"      ],      "Resource": "arn:aws:s3:::my-images/*"    }  ]}
  1. Создайте пользователя IAM для CloudFront (это может быть тот же пользователь) с такой политикой. cloudfront:GetDistribution необязательно; с этим правом smallPict может определить домен дистрибутива, если вы оставите домен CDN пустым.
JSON
{  "Version": "2012-10-17",  "Statement": [    {      "Effect": "Allow",      "Action": [        "cloudfront:CreateInvalidation",        "cloudfront:GetDistribution"      ],      "Resource": "arn:aws:cloudfront::123456789012:distribution/E2QWRUHAPOMQZL"    }  ]}
  1. В панели управления:
    • Провайдер хранилища Amazon S3, бакет my-images, регион ap-southeast-1, эндпоинт пустой (используется стандартный эндпоинт региона), а также access key ID и секрет для хранилища.
    • CDN Amazon CloudFront, Distribution ID (например, E2QWRUHAPOMQZL), access key ID и секрет для CloudFront и, при желании, домен CDN (https://images.example.com). Оставьте домен пустым, чтобы использовать собственный домен дистрибутива *.cloudfront.net.

B. Cloudflare R2 + Cloudflare

  1. Создайте бакет R2, например my-images.
  2. Подключите к бакету собственный домен (R2 → ваш бакет → Settings → Custom Domains), например images.example.com, в зоне того же аккаунта Cloudflare. Запросы к этому домену проходят через кеш Cloudflare. Не используйте URL разработки r2.dev в продакшене.
  3. Создайте API-токен R2 (R2 → Manage API tokens) с правом Object Read & Write, ограниченный только этим бакетом. Скопируйте показанные Access Key ID и Secret Access Key.
  4. Создайте API-токен Cloudflare (My Profile → API Tokens) для зоны с правом Zone → Cache Purge → Purge. Zone → Zone → Read — необязательно.
  5. В панели управления:
    • Провайдер хранилища Cloudflare R2, бакет my-images, эндпоинт https://<account_id>.r2.cloudflarestorage.com (указан в параметрах S3 API вашего бакета), регион auto, а также Access Key ID и Secret Access Key от R2.
    • CDN Cloudflare, Zone ID (страница Overview домена, раздел API), API-токен и домен CDN https://images.example.com.

C. Google Cloud Storage + Cloudflare

Google Cloud Storage подключается через свой S3-совместимый XML API с ключами HMAC.

  1. Создайте бакет, например my-images.
  2. Создайте сервисный аккаунт и выдайте ему роль Storage Object User (roles/storage.objectUser) только на этот бакет.
  3. Создайте ключ HMAC для сервисного аккаунта: Cloud Storage → Settings → Interoperability → Create a key for a service account. Скопируйте access ID и секрет.
  4. Сделайте оптимизированные файлы доступными для чтения вашему CDN. Cloudflare получает файлы из Cloud Storage по HTTPS, поэтому объекты в optimized/ должны быть публично читаемыми. При единообразном доступе на уровне бакета (uniform bucket-level access) выдача allUsers роли Storage Object Viewer делает читаемым весь бакет, включая originals/. Если оригиналы должны оставаться приватными, поставьте перед бакетом слой аутентификации (например, Cloudflare Worker, который подписывает запросы к бакету).
  5. Направьте проксируемую DNS-запись Cloudflare на Cloud Storage, например images.example.com. Либо назовите бакет по имени хоста и используйте проксируемую CNAME-запись на c.storage.googleapis.com, либо используйте Cloudflare Origin Rule, которое отправляет запросы на storage.googleapis.com с именем бакета в начале пути.
  6. Создайте API-токен Cloudflare для зоны с правом Zone → Cache Purge → Purge (Zone → Zone → Read — необязательно).
  7. В панели управления: провайдер хранилища Google Cloud Storage, бакет, эндпоинт https://storage.googleapis.com, регион auto, access ID и секрет HMAC; CDN Cloudflare, Zone ID, API-токен и домен CDN https://images.example.com.

D. MinIO или любое S3-совместимое хранилище + Cloudflare

Этот раздел охватывает MinIO и S3-совместимые сервисы, такие как Hetzner, Wasabi, Vultr, SumoPod, Alibaba Cloud OSS, Tencent Cloud COS и DigitalOcean Spaces.

ПровайдерЧто выбрать в панелиЭндпоинтПримечания
MinIOMinIOВаш сервер, например https://minio.example.comPath-style запросы включены. Сервер должен быть доступен из интернета по HTTPS.
Hetzner Object StorageДругое S3-совместимоеhttps://<location>.your-objectstorage.com
WasabiДругое S3-совместимоеhttps://s3.<region>.wasabisys.com
Vultr Object StorageДругое S3-совместимоеhttps://<region>.vultrobjects.com
SumoPod StorageSumoPod StorageИз панели хранилища SumoPodPath-style включён по умолчанию.
Alibaba Cloud OSSAlibaba Cloud OSShttps://oss-<region>.aliyuncs.comТолько стиль virtual-hosted.
Tencent Cloud COSTencent Cloud COShttps://cos.<region>.myqcloud.comИмя бакета включает ваш APPID, например my-images-1250000000.
DigitalOcean SpacesDigitalOcean Spaceshttps://<region>.digitaloceanspaces.com
  1. Создайте бакет и ключ, ограниченный этим бакетом, с правами на запись, чтение и удаление объектов (см. Минимальные права ниже).
  2. Сделайте optimized/ доступным для чтения вашему CDN, например политикой бакета, которая разрешает анонимный s3:GetObject только для optimized/*. В MinIO:
JSON
{  "Version": "2012-10-17",  "Statement": [    {      "Effect": "Allow",      "Principal": {        "AWS": [          "*"        ]      },      "Action": [        "s3:GetObject"      ],      "Resource": [        "arn:aws:s3:::my-images/optimized/*"      ]    }  ]}
  1. Поставьте Cloudflare перед бакетом: проксируемая DNS-запись для images.example.com, указывающая на публичный хост бакета. Если провайдеру нужен его собственный хост в запросе, добавьте Cloudflare Origin Rule, которое переписывает заголовок Host (а для path-style хостов добавляет имя бакета в путь).
  2. Создайте API-токен Cloudflare для зоны с правом Zone → Cache Purge → Purge (Zone → Zone → Read — необязательно).
  3. В панели управления: выберите провайдера из таблицы, укажите бакет, эндпоинт, регион (auto, если у провайдера его нет) и ключи; включите path-style запросы там, где это указано в таблице; затем CDN Cloudflare, Zone ID, API-токен и домен CDN.

Минимальные права

Выдайте smallPict ключи, которые могут делать только необходимое и только в одном бакете.

ПровайдерПрава
Amazon S3s3:PutObject, s3:GetObject, s3:DeleteObject на arn:aws:s3:::<bucket>/*
Amazon CloudFrontcloudfront:CreateInvalidation на дистрибутив; необязательно cloudfront:GetDistribution, чтобы домен определялся автоматически
Cloudflare R2API-токен R2 с правом Object Read & Write, ограниченный бакетом
Cloudflare (CDN)API-токен для зоны с правом Zone → Cache Purge → Purge; необязательно Zone → Zone → Read
Google Cloud StorageКлюч HMAC для сервисного аккаунта с roles/storage.objectUser на бакет
Alibaba Cloud OSSПользователь RAM с oss:PutObject, oss:GetObject, oss:DeleteObject на бакет
Tencent Cloud COSСубпользователь CAM с cos:PutObject, cos:GetObject, cos:DeleteObject на бакет (имя бакета включает APPID)
DigitalOcean SpacesКлюч доступа Spaces, ограниченный бакетом, с правами на чтение, запись и удаление
MinIO / другое S3-совместимоеЗапись, чтение и удаление для <bucket>/*; эндпоинт должен быть публичным HTTPS

Проверка подключения

При каждом сохранении (и при нажатии Повторить проверку) smallPict проверяет всё подключение, прежде чем его использовать:

  1. Хранилище: записывает небольшой тестовый файл в .smallpict-probe/ в вашем бакете, считывает его и удаляет.
  2. Cloudflare: отправляет в вашу зону одну тестовую очистку кеша для одного URL.
  3. CloudFront: создаёт одну тестовую инвалидацию для пути /.smallpict-probe/.... Она учитывается в месячном количестве путей инвалидации CloudFront.

Если какой-либо шаг не пройден, ничего не переключается. Панель показывает причину рядом с соответствующим полем, например у имени бакета или API-токена. Проверка подключения ограничена 5 попытками в минуту.


Доступ CDN к бакету

  • optimized/ должен быть доступен вашему CDN для чтения: либо публичное чтение для этого префикса, либо доступ CDN к приватному бакету через источник (origin access control в CloudFront или собственный домен R2).
  • originals/ может оставаться приватным. Вашему CDN он никогда не нужен.
  • CORS нужен, только если браузеры загружают изображения с другого источника из JavaScript (например, через fetch() или canvas). Обычным тегам <img> он не нужен. Если он всё же нужен, разрешите GET и HEAD с источника вашего сайта.

Структура объектов и URL

ЧтоКлюч в вашем бакетеURL
Оригиналoriginals/<job_id>/<file>Не отдаётся
Оптимизированный файлoptimized/<job_id>.<ext><cdn_domain>/optimized/<job_id>.<ext>

Домен CDN может содержать префикс пути, например https://example.com/images; тогда URL будет https://example.com/images/optimized/<job_id>.<ext>.


Заголовки кеширования

Оптимизированные файлы записываются с заголовком Cache-Control: public, max-age=31536000, immutable. Каждое задание получает уникальный ключ, поэтому новый результат всегда имеет новый URL и очистка кеша нужна редко. Следите, чтобы правила кеширования вашего CDN не заменяли этот заголовок более коротким сроком.


Очистка кеша

  • Запросы на очистку через API (POST /v1/purge) отправляются в ваш CDN пакетами.
  • В Cloudflare файлы очищаются по URL. «Очистить всё» очищает только ваш хост доставки и префикс пути, а не всю зону.
  • В CloudFront файлы очищаются инвалидациями. «Очистить всё» создаёт инвалидацию /*. Пути инвалидации сверх месячного бесплатного лимита CloudFront AWS выставляет в счёт вашему аккаунту.

Смена режима

Смена режима не перемещает существующие файлы. Уже доставленные файлы сохраняют свои текущие URL; новый режим применяется только к новым заданиям.

  • Управляемый → BYO: новые задания записываются в ваш бакет и отдаются вашим CDN. Файлы, уже находящиеся на cdn.smallpict.app, остаются там.
  • BYO → управляемый: новые задания снова используют управляемое хранилище и CDN. Ваши настройки и ключи BYO остаются сохранёнными, но не используются, поэтому вы можете переключиться обратно без повторного ввода, пока не нажмёте Отключить.
  • Отключить: удаляет сохранённые ключи и настройки BYO и возвращает вас в управляемый режим. Файлы в вашем бакете не затрагиваются.

Если что-то пошло не так

  • Если smallPict не может записать файл в ваш бакет, он повторяет попытки, а затем завершает задание с ошибкой и указывает причину в ответе API.
  • Панель показывает последнюю ошибку и время, когда она произошла, вместе с кнопкой Повторить проверку.
  • Вы получаете одно письмо на инцидент, а не на каждое неудачное задание.
  • smallPict никогда не переключается на управляемое хранилище автоматически. Ваши файлы никогда не хранятся там, где вы этого не выбирали.

Безопасность

  • Ключи хранятся в зашифрованном хранилище секретов. Они больше никогда не показываются, не возвращаются через API и не записываются в логи.
  • Чтобы заменить ключ, введите новый и сохраните; проверка подключения выполнится с новым ключом. Оставьте поле ключа пустым, чтобы сохранить текущий ключ.
  • Эндпоинты хранилища и CDN должны использовать HTTPS. Эндпоинты, которые разрешаются в частные, loopback, link-local или другие внутренние адреса, отклоняются.
  • Используйте для smallPict отдельные ключи с узкими правами и отзовите их в консоли провайдера, если перестанете пользоваться BYO.