Cloudflare R2 — об'єктне сховище, сумісне з S3 API. Головна відмінність від Amazon S3: немає плати за egress (вихідний трафік). Чудово підходить для зберігання зображень, відео, бекапів.
Тарифи R2
| Ресурс | Free | Paid |
|---|---|---|
| Сховище | 10 ГБ/міс | $0.015/ГБ |
| Class A операції (PUT) | 1 млн/міс | $4.50/млн |
| Class B операції (GET) | 10 млн/міс | $0.36/млн |
| Egress трафік | Безкоштовно ✅ | Безкоштовно ✅ |
Створення бакета R2
R2 → Create bucket → введіть ім'я → Create bucket.
Для публічного доступу (CDN): Settings → Public Access → Allow Access.
# URL публічного файлу:
https://pub-HASH.r2.dev/folder/filename.jpg
# Або кастомний домен:
https://media.example.com/folder/filename.jpg
Завантаження файлів через S3 API
# Налаштувати aws-cli для R2
aws configure --profile cloudflare
# AWS Access Key ID: R2 Access Key
# AWS Secret Access Key: R2 Secret Key
# Default region: auto
# Завантажити файл
aws s3 cp file.jpg s3://my-bucket/file.jpg --endpoint-url https://ACCOUNT_ID.r2.cloudflarestorage.com --profile cloudflare
# Синхронізувати папку
aws s3 sync ./media/ s3://my-bucket/ --endpoint-url https://ACCOUNT_ID.r2.cloudflarestorage.com --profile cloudflare
WordPress + R2 через плагін
Використовуйте плагін «Media Cloud» або «Offload Media» з налаштуваннями R2:
- Storage Provider: S3 Compatible
- Endpoint: https://ACCOUNT_ID.r2.cloudflarestorage.com
- Region: auto
R2 порівняно з S3 і локальним диском
| Критерій | R2 | Amazon S3 | Локальний диск сервера |
|---|---|---|---|
| Плата за egress | Немає | Є, за обсягом | Немає (входить у тариф сервера) |
| S3-сумісний API | Так | Так (еталон) | Ні |
| Вбудований CDN | Через Cloudflare | Потрібен окремо CloudFront | Немає |
| Обмеження за місцем | Практично немає | Практично немає | Розмір диска VPS |
Розбір типових помилок
Access Denied під час завантаження через S3 API
Найчастіше означає, що R2 Access Key і Secret Key не збігаються з бакетом (ключі прив'язані до конкретного акаунта Cloudflare, а не глобальні), або endpoint URL вказано з помилкою — у ньому обов'язковий саме Account ID, а не назва бакета чи домену.
CORS-помилка під час звернення до бакета з браузера
Якщо файли з R2 завантажуються напряму JS-кодом на клієнті (не просто як <img src>), потрібно налаштувати CORS-політику бакета: Settings → CORS Policy → вказати дозволені Origin, методи й заголовки. Без цього браузер блокує відповідь на рівні Same-Origin Policy, навіть якщо сам файл віддається з кодом 200.
Перевірка результату
# Перевірити що публічний доступ до файлу працює
curl -I https://pub-HASH.r2.dev/folder/filename.jpg
# Очікувано: HTTP/2 200, content-type: image/jpeg
# Перевірити список об'єктів через aws-cli
aws s3 ls s3://my-bucket/ --endpoint-url https://ACCOUNT_ID.r2.cloudflarestorage.com --profile cloudflare
Коли R2 не підходить
- Потрібна активна вибірка і складні запити за метаданими файлів — R2, як і S3, це об'єктне сховище, а не база даних, для пошуку потрібен окремий індекс.
- Потрібна файлова система з блокуваннями й одночасним записом з кількох серверів в один файл — об'єктні сховища не для цього, потрібен NFS чи спільний диск.
- Зберігаються зображення чи відео і потрібна обробка на льоту (ресайз, транскодинг) — для цього більше підходить Cloudflare Images/Stream, ніж сирий R2-бакет.
R2 підтримує Object Lifecycle Rules — можна налаштувати автоматичне видалення об'єктів старших за певний строк (наприклад, тимчасові бекапи) або переведення у дешевший клас зберігання. Правила налаштовуються в Settings бакета → Object lifecycle rules.
Для тимчасового доступу до приватних файлів без увімкнення повного публічного доступу використовуйте presigned URL — підписане посилання з обмеженим терміном дії, яке генерує SDK чи aws-cli через той самий S3-сумісний API. Таке посилання віддає файл напряму, без проходження через ваш сервер.
Перенести наявний бакет з Amazon S3 на R2 можна утилітою rclone або звичайним aws s3 sync, вказавши обидва endpoint — початковий і ACCOUNT_ID.r2.cloudflarestorage.com. Для великих обсягів даних перенесення варто робити частинами, щоб не впертися в ліміти запитів за раз.
Витрату по операціях Class A і Class B, а також обсяг сховища видно в Dashboard → R2 → Metrics по кожному бакету окремо — зручно, якщо кілька проєктів використовують спільний акаунт Cloudflare і потрібно розуміти, що саме генерує навантаження.
Під час створення бакета можна обрати jurisdiction (наприклад, EU) — це гарантує, що дані фізично не залишають обраний регіон, що важливо для проєктів із вимогами щодо локалізації даних на кшталт GDPR.