По умолчанию загруженные файлы (вложения поддержки, изображения FAQ, файлы партнёров, PWA-ассеты) хранятся локально в ./uploads. Используйте S3-совместимое хранилище для масштабируемости и надёжности.
Настройка
Шаг 1: Добавьте настройки S3 в .env
# S3 Storage
S3_ENABLED=true
S3_ENDPOINT=http://rustfs:9000
S3_ACCESS_KEY=your_access_key
S3_SECRET_KEY=your_secret_key
S3_PUBLIC_URL=https://s3.example.com
S3_REGION=us-east-1
S3_BUCKET=filesШаг 2: Добавьте переменные S3 в сервис бота
Убедитесь, что в compose.yaml в секции environment сервиса бота прокинуты все S3-переменные:
environment:
- S3_ENABLED=${S3_ENABLED}
- S3_ENDPOINT=${S3_ENDPOINT}
- S3_ACCESS_KEY=${S3_ACCESS_KEY}
- S3_SECRET_KEY=${S3_SECRET_KEY}
- S3_PUBLIC_URL=${S3_PUBLIC_URL}
- S3_REGION=${S3_REGION}
- S3_BUCKET=${S3_BUCKET}Внимание
Без этих переменных контейнер бота не будет знать о настройках S3, даже если они указаны в .env. Docker Compose передаёт в контейнер только те переменные, которые явно перечислены в секции environment.
Шаг 3: Выберите провайдера S3
Используйте один из вариантов ниже.
RustFS (self-hosted)
Добавьте сервис в compose.yaml:
rustfs:
image: rustfs/rustfs:latest
container_name: rwp_shop_rustfs
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
- RUSTFS_ROOT_USER=your_access_key
- RUSTFS_ROOT_PASSWORD=your_secret_key
volumes:
- rustfs_data:/data
ports:
- "127.0.0.1:9001:9001"
networks:
- remnawave-networkДобавьте volume:
volumes:
rwp_shop_db_data:
rustfs_data:Опубликуйте публичный URL (нужен для presigned URLs) через reverse proxy:
s3.example.com {
import security_headers
reverse_proxy rustfs:9000
}server {
listen 443 ssl http2;
server_name s3.example.com;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_set_header Host $host;
client_max_body_size 100M;
}
}Yandex Object Storage
Создайте бакет в Yandex Cloud → Object Storage. Получите статический ключ доступа в сервисном аккаунте с ролью storage.editor.
# Yandex Object Storage
S3_ENABLED=true
S3_ENDPOINT=https://storage.yandexcloud.net
S3_ACCESS_KEY=<KEY_ID>
S3_SECRET_KEY=<SECRET>
S3_PUBLIC_URL=https://<BUCKET>.storage.yandexcloud.net
S3_REGION=ru-central1
S3_BUCKET=<BUCKET>Для публичного доступа включите ACL public-read на бакете или используйте Website hosting. Подключите свой домен через CNAME <BUCKET>.website.yandexcloud.net.
VK Cloud (Hotbox)
В панели VK Cloud → Cloud Storage создайте проект и Hotbox-бакет. Сгенерируйте S3 ключи в разделе аккаунта.
# VK Cloud Hotbox
S3_ENABLED=true
S3_ENDPOINT=https://hb.ru-msk.vkcs.cloud
S3_ACCESS_KEY=<ACCESS_KEY>
S3_SECRET_KEY=<SECRET_KEY>
S3_PUBLIC_URL=https://<BUCKET>.hb.ru-msk.vkcs.cloud
S3_REGION=ru-msk
S3_BUCKET=<BUCKET>Icebox дешевле, но не подходит — латентность высокая. Используйте только Hotbox.
Selectel Object Storage
Создайте контейнер в панели Selectel → Облачное хранилище. Выберите тип «S3-совместимый». Сгенерируйте сервисного пользователя с ключами S3.
# Selectel Object Storage
S3_ENABLED=true
S3_ENDPOINT=https://s3.ru-1.storage.selcloud.ru
S3_ACCESS_KEY=<ACCESS_KEY>
S3_SECRET_KEY=<SECRET_KEY>
S3_PUBLIC_URL=https://<BUCKET>.s3.ru-1.storage.selcloud.ru
S3_REGION=ru-1
S3_BUCKET=<BUCKET>Для публичных файлов установите контейнеру тип «публичный» в панели. Альтернативно — подключите CDN Selectel.
Timeweb Cloud Storage
В панели Timeweb Cloud → Облачное хранилище создайте бакет. Ключи доступа в разделе «API и интеграции».
# Timeweb Cloud Storage
S3_ENABLED=true
S3_ENDPOINT=https://s3.timeweb.cloud
S3_ACCESS_KEY=<ACCESS_KEY>
S3_SECRET_KEY=<SECRET_KEY>
S3_PUBLIC_URL=https://<BUCKET>.s3.timeweb.cloud
S3_REGION=ru-1
S3_BUCKET=<BUCKET>Установите политику бакета public-read через AWS CLI, либо включите публичный доступ в панели.
Cloud.ru Evolution Object Storage
Создайте бакет в Cloud.ru → Evolution Object Storage. Сгенерируйте ключи в IAM.
# Cloud.ru Evolution Object Storage
S3_ENABLED=true
S3_ENDPOINT=https://s3.cloud.ru
S3_ACCESS_KEY=<TENANT_ID>:<KEY_ID>
S3_SECRET_KEY=<SECRET>
S3_PUBLIC_URL=https://<BUCKET>.s3.cloud.ru
S3_REGION=ru-central-1
S3_BUCKET=<BUCKET>S3_ACCESS_KEY формируется как <tenant_id>:<key_id> — особенность Cloud.ru. Публичный доступ настраивается через политику бакета.
Cloudflare R2
Создайте бакет и S3 API ключи в панели Cloudflare. R2 использует S3-совместимый endpoint формата https://<ACCOUNT_ID>.r2.cloudflarestorage.com.
# Cloudflare R2
S3_ENABLED=true
S3_ENDPOINT=https://<ACCOUNT_ID>.r2.cloudflarestorage.com
S3_ACCESS_KEY=<R2_ACCESS_KEY_ID>
S3_SECRET_KEY=<R2_SECRET_ACCESS_KEY>
S3_PUBLIC_URL=https://<YOUR_PUBLIC_BUCKET_URL>
S3_REGION=auto # R2 использует "auto" как регион
S3_BUCKET=files # рекомендуется для R2 free tier (лимит бакетов)S3_PUBLIC_URL должен указывать на публичный URL бакета, включённый в R2 (custom domain или управляемый r2.dev). Egress бесплатный — выгодно для раздачи медиа.
Настройка CORS
Для прямой загрузки/скачивания через presigned URLs настройте CORS на бакете. Пример правила:
[
{
"AllowedOrigins": ["https://your-domain.com"],
"AllowedMethods": ["GET", "PUT", "HEAD"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 86400
}
]Замените https://your-domain.com на домен фронтенда/Mini App. Для wildcard поддоменов: https://*.your-domain.com.
Шаг 4: Перезапустите бота
docker compose up -dПримечание
Переменные окружения
| Переменная | Описание |
|---|---|
S3_ENABLED | Включить S3 хранилище (true/false) |
S3_ENDPOINT | Endpoint S3 API |
S3_ACCESS_KEY | Ключ доступа S3 |
S3_SECRET_KEY | Секретный ключ S3 |
S3_PUBLIC_URL | Публичный HTTPS URL для presigned URLs |
S3_REGION | Регион S3 (по умолчанию: us-east-1). Требуется для AWS и некоторых S3-совместимых провайдеров |
S3_BUCKET | Опциональное имя родительского бакета. Если задано, все логические бакеты становятся префиксами ключей внутри одного бакета |
Внимание
S3_PUBLIC_URL обязателенS3_PUBLIC_URL должен быть публичным HTTPS URL. Он используется для генерации presigned URLs для прямых скачиваний файлов.