К основному содержимому

S3 Object Storage: сравнение провайдеров и интеграция с PHP

Облако и DevOps · 19.04.2026 · 3 мин чтения
Иллюстрация к статье «S3 Object Storage: сравнение провайдеров и интеграция с PHP»

Облачное хранилище объектов: сравнение S3-провайдеров

Объектное хранилище (Object Storage) — оптимальный способ хранить статику, медиафайлы, бэкапы и ML-датасеты. Все провайдеры используют совместимый с S3 API, что упрощает смену провайдера.

Сравнение S3-провайдеров

ПровайдерЦена (GB/мес)Трафик исходящийРегион
Hetzner Object Storage€0.0049€0.010/GB (первые 1TB бесплатно)Германия, Финляндия
Backblaze B2$0.006$0.01/GBСША, ЕС
Cloudflare R2$0.015БЕСПЛАТНОГлобально
DigitalOcean Spaces$0.020$0.01/GB (первые 1TB бесплатно)США, ЕС, Азия
AWS S3$0.023$0.09/GBГлобально

Cloudflare R2: бесплатный исходящий трафик

# R2 через rclone
[cloudflare-r2]
type = s3
provider = Cloudflare
access_key_id = YOUR_R2_ACCESS_KEY
secret_access_key = YOUR_R2_SECRET_KEY
endpoint = https://ACCOUNT_ID.r2.cloudflarestorage.com
region = auto

Подключение к WordPress (WP Offload Media)

# wp-config.php
define('AS3CF_SETTINGS', serialize([
    'provider'    => 's3',
    'access-key-id'     => 'YOUR_KEY',
    'secret-access-key' => 'YOUR_SECRET',
    'bucket'      => 'my-wp-media',
    'region'      => 'eu-central-1',
    'domain'      => 'path',  // или custom domain через CDN
]));

PHP: загрузка файлов в S3

use Aws\S3\S3Client;

$s3 = new S3Client([
    'version'     => 'latest',
    'region'      => 'eu-central-1',
    'endpoint'    => 'https://YOUR_ENDPOINT',
    'credentials' => ['key' => 'KEY', 'secret' => 'SECRET'],
    'use_path_style_endpoint' => true,
]);

// Загрузить файл
$s3->putObject([
    'Bucket'      => 'my-bucket',
    'Key'         => 'uploads/' . basename($_FILES['file']['name']),
    'SourceFile'  => $_FILES['file']['tmp_name'],
    'ACL'         => 'public-read',
    'ContentType' => $_FILES['file']['type'],
]);

// Получить публичный URL
$url = $s3->getObjectUrl('my-bucket', 'uploads/photo.jpg');
Рекомендация: Для европейских клиентов используйте Hetzner Object Storage (дешевле всего при хранении) или Cloudflare R2 (если важен исходящий трафик). Оба совместимы с AWS S3 SDK.

Разбор реальных ошибок S3 API

Два сообщения об ошибках встречаются чаще всего у новичков в объектных хранилищах, и оба не связаны с сетью или квотами.

SignatureDoesNotMatch

<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message></Error>

Классические причины: неверный secret key (лишний пробел при копировании), рассинхронизация системных часов сервера более чем на 15 минут, либо не выставлен use_path_style_endpoint => true для провайдеров, которые не поддерживают virtual-hosted style (MinIO, Hetzner). Проверьте время командой timedatectl и синхронизируйте через chronyd или ntpd.

AccessControlListNotSupported

<Error><Code>AccessControlListNotSupported</Code><Message>The bucket does not allow ACLs</Message></Error>

С апреля 2023 года новые бакеты AWS S3 создаются с Object Ownership Bucket owner enforced, который полностью отключает ACL. Код с 'ACL' => 'public-read' в putObject начинает падать с этой ошибкой. Решение — убрать параметр ACL и открыть доступ через bucket policy в JSON вместо ACL на уровне объекта.

Когда объектное хранилище не подходит

  • Нужна POSIX-семантика с блокировками файлов и атомарной дозаписью — S3 это не файловая система, а хранилище неизменяемых объектов целиком.
  • Приложению нужна низкая задержка для блочного доступа базы данных — используйте локальный NVMe или сетевой блочный диск, а не объектное API.
  • Хранится огромное количество очень мелких файлов с высокой частотой запросов — биллинг за операции (PUT/GET) начинает превышать биллинг за объём, разумнее объединять файлы или ставить CDN-кэш перед бакетом.
  • Нужна запись в реальном времени с минимальной задержкой (потоковое видео, телеметрия) — объектное хранилище проектировалось для батчевой записи, а не для потока.
  • Регуляторные требования обязывают физический контроль над носителем — тогда разворачивайте собственный MinIO на своём железе вместо облачного провайдера.

Проверка результата

# Загрузить тестовый файл и сверить контрольную сумму
aws s3 cp test.txt s3://my-bucket/test.txt --endpoint-url https://YOUR_ENDPOINT
aws s3api head-object --bucket my-bucket --key test.txt --endpoint-url https://YOUR_ENDPOINT

# Проверить публичный доступ, если бакет должен быть открыт
curl -I https://my-bucket.YOUR_ENDPOINT/test.txt

# Сравнить локальный и удалённый MD5
md5sum test.txt
aws s3api head-object --bucket my-bucket --key test.txt --query ETag --endpoint-url https://YOUR_ENDPOINT

Код ответа 403 на публичный curl -I почти всегда означает, что bucket policy не разрешает анонимное чтение, а не проблему с ключами доступа — ключи вообще не нужны для чтения публичного объекта. Если объектное хранилище используется для бэкапов, логичнее гонять их через rclone, а не писать код на PHP под разовую задачу.

Статья помогла?
← Назад в базу знаний Задать вопрос поддержке