Эта тема описывает настройку некоторых популярных провайдеров объектного хранилища, совместимых с S3 (аналоги S3). Подробнее о конфигурации Amazon AWS S3, которая официально поддерживается и используется внутри Discourse для наших хостинг-услуг, см. по ссылке: Set up file and image uploads to S3.
| Провайдер | Название сервиса | Работает с Discourse? |
|---|---|---|
| Amazon AWS | S3 | Да |
| Digital Ocean | Spaces | Да |
| Linode | Object Storage | Да |
| Google Cloud | Storage | Да |
| Scaleway | Object Storage | Да |
| Vultr | Object Storage | Да |
| BackBlaze | Cloud Storage | Да* |
| Самохостинг | MinIO | Да |
| Azure Blob Storage | Flexify.IO | Да |
| Oracle Cloud | Object Storage | Нет [1] |
| Wasabi | Object Storage | Возможно |
| Cloudflare | R2 | Да |
| Contabo | Object Storage | Нет |
Если вам удалось заставить работать другой сервис, пожалуйста, добавьте его в эту вики.
Конфигурация
Чтобы хранить статические ресурсы Discourse в вашем объектном хранилище, добавьте следующую конфигурацию в файл app.yml в секцию hooks:
after_assets_precompile:
- exec:
cd: $home
cmd:
- sudo -E -u discourse bundle exec rake s3:upload_assets
- sudo -E -u discourse bundle exec rake s3:expire_missing_assets
При использовании объектного хранилища вам также потребуется CDN для обслуживания файлов, хранящихся в бакете. В моих тестах я использовал CDN StackPath; кроме необходимости установить параметр Dynamic Caching By Header: Accept-Encoding в их конфигурации, всё работает нормально.
DISCOURSE_CDN_URL — это CDN, указывающий на доменное имя вашего Discourse и кэширующий запросы. Он будет использоваться в основном для «pullable» ресурсов: CSS и других тематических ресурсов.
DISCOURSE_S3_CDN_URL — это CDN, указывающий на ваш бакет объектного хранилища и кэширующий запросы. Он будет использоваться в основном для «pushable» ресурсов: JS, изображений и загрузок пользователей.
Мы рекомендуем, чтобы эти значения различались, и администраторам следует устанавливать оба.
Неиспользование CDN (или указание URL бакета в качестве URL CDN) скорее всего вызовет проблемы и не поддерживается.
В следующих примерах https://falcoland-files-cdn.falco.dev — это CDN, настроенный для обслуживания файлов из бакета. В моих примерах имя бакета было установлено как falcoland-files.
Рекомендуется настраивать эти параметры в переменных окружения в вашем файле app.yml, так как именно так CDCK делает это в своей инфраструктуре, что означает, что решение хорошо протестировано. Кроме того, задача загрузки ресурсов выполняется после компиляции ресурсов, что происходит при пересборке. Если вы хотите запустить Discourse, который корректно работает с объектным хранилищем с самого начала, вам необходимо установить переменные окружения, чтобы ресурсы были загружены до запуска сайта.
Выберите своего провайдера из списка ниже и добавьте эти настройки в секцию env вашего файла app.yml, соответствующим образом изменив значения:
AWS S3
То, что мы официально поддерживаем и используем внутри. Их CDN-предложение CloudFront также подходит для обслуживания файлов из бакета. См. Set up file and image uploads to S3 для инструкций по правильной настройке прав доступа.
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: us-west-1
DISCOURSE_S3_ACCESS_KEY_ID: myaccesskey
DISCOURSE_S3_SECRET_ACCESS_KEY: mysecretkey
DISCOURSE_S3_CDN_URL: https://falcoland-files-cdn.falco.dev
DISCOURSE_S3_BUCKET: falcoland-files
DISCOURSE_S3_BACKUP_BUCKET: falcoland-files/backups
DISCOURSE_BACKUP_LOCATION: s3
Digital Ocean Spaces
Предложение DO хорошее и работает из коробки. Можно включить ограничение на listing файлов. Единственная проблема в том, что их CDN-предложение ужасно неработоспособно, поэтому вам нужно использовать другой CDN для файлов. Также вам не нужно устанавливать правило CORS, так как оно переустанавливается при каждой пересборке.
Пример конфигурации:
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: whatever
DISCOURSE_S3_ENDPOINT: https://nyc3.digitaloceanspaces.com
DISCOURSE_S3_ACCESS_KEY_ID: myaccesskey
DISCOURSE_S3_SECRET_ACCESS_KEY: mysecretkey
DISCOURSE_S3_CDN_URL: https://falcoland-files-cdn.falco.dev
DISCOURSE_S3_BUCKET: falcoland-files
DISCOURSE_S3_BACKUP_BUCKET: falcoland-files/backups
DISCOURSE_BACKUP_LOCATION: s3
DISCOURSE_S3_INSTALL_CORS_RULE: false
Linode Object Storage
Для Linode требуется дополнительный параметр конфигурации: HTTP_CONTINUE_TIMEOUT.
Пример конфигурации:
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: us-east-1
DISCOURSE_S3_HTTP_CONTINUE_TIMEOUT: 0
DISCOURSE_S3_ENDPOINT: https://us-east-1.linodeobjects.com
DISCOURSE_S3_ACCESS_KEY_ID: myaccesskey
DISCOURSE_S3_SECRET_ACCESS_KEY: mysecretkey
DISCOURSE_S3_CDN_URL: https://falcoland-files-cdn.falco.dev
DISCOURSE_S3_BUCKET: falcoland-files
DISCOURSE_S3_BACKUP_BUCKET: falcoland-files/backup
DISCOURSE_BACKUP_LOCATION: s3
Google Cloud Platform Storage
Список файлов не работает, поэтому вам нужна дополнительная переменная окружения, чтобы пропустить это, чтобы ресурсы работали. Также пропустите CORS и настройте его вручную.
Поскольку вы не можете перечислять файлы, вы не сможете перечислять резервные копии, и автоматические резервные копии будут неудачными. Мы не рекомендуем использовать это для резервного копирования. Однако некоторые пользователи предполагают, что если изменить роль с Storage Legacy Object Owner на Storage Legacy Bucket Owner, резервные копии будут работать корректно. См. эту тему для обсуждения, специфичного для Google Cloud.
Существует сторонний плагин для улучшения интеграции по адресу Discourse GCS Helper.
Пример конфигурации:
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: us-east1
DISCOURSE_S3_INSTALL_CORS_RULE: false
FORCE_S3_UPLOADS: 1
DISCOURSE_S3_ENDPOINT: https://storage.googleapis.com
DISCOURSE_S3_ACCESS_KEY_ID: myaccesskey
DISCOURSE_S3_SECRET_ACCESS_KEY: mysecretkey
DISCOURSE_S3_CDN_URL: https://falcoland-files-cdn.falco.dev
DISCOURSE_S3_BUCKET: falcoland-files
#DISCOURSE_S3_BACKUP_BUCKET: falcoland-files/backup
#DISCOURSE_BACKUP_LOCATION: s3
Scaleway Object Storage
Предложение Scaleway также очень хорошее, и всё работает нормально в большинстве случаев.
Загрузка multipart в Scaleway поддерживает максимум 1000 частей. Это не совпадает с Amazon S3, который поддерживает максимум 10 000 частей. Для более крупных экземпляров это приведет к неудачам резервного копирования Discourse, и незавершенную загрузку может потребоваться удалить вручную перед повторными попытками. Для небольших экземпляров это не проблема. Scaleway кажется довольно открытым к обратной связи, поэтому, если вы хотите изменить этот лимит, свяжитесь с ними.
Обратите внимание, что для параметра DISCOURSE_S3_ENDPOINT Discourse использует конечную точку всего региона: https://s3.{region}.scw.cloud. «Конечная точка бакета», найденная в вашей панели управления Scaleway, имеет вид https://{bucketName}.s3.{region}.scw.cloud. Пропустите поддомен имени бакета, чтобы избежать ошибок подключения.
Пример конфигурации:
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: fr-par
DISCOURSE_S3_ENDPOINT: https://s3.fr-par.scw.cloud
DISCOURSE_S3_ACCESS_KEY_ID: myaccesskey
DISCOURSE_S3_SECRET_ACCESS_KEY: mysecretkey
DISCOURSE_S3_CDN_URL: https://falcoland-files-cdn.falco.dev
DISCOURSE_S3_BUCKET: falcoland-files
DISCOURSE_S3_BACKUP_BUCKET: falcoland-files/backups
DISCOURSE_BACKUP_LOCATION: s3
Vultr Object Storage
Для Vultr требуется дополнительный параметр конфигурации: HTTP_CONTINUE_TIMEOUT.
Пример конфигурации:
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: whatever
DISCOURSE_S3_HTTP_CONTINUE_TIMEOUT: 0
DISCOURSE_S3_ENDPOINT: https://ewr1.vultrobjects.com
DISCOURSE_S3_ACCESS_KEY_ID: myaccesskey
DISCOURSE_S3_SECRET_ACCESS_KEY: mysecretkey
DISCOURSE_S3_CDN_URL: https://falcoland-files-cdn.falco.dev
DISCOURSE_S3_BUCKET: falcoland-files
DISCOURSE_S3_BACKUP_BUCKET: falcoland-files/backup
DISCOURSE_BACKUP_LOCATION: s3
Backblaze B2 Cloud Storage
Вам нужно пропустить CORS и настроить его вручную.
Существуют отчеты о том, что функция clean up orphan uploads не работает корректно с BackBlaze. Вы должны изменить правила жизненного цикла для вашего бакета, чтобы очистка сиротских файлов работала.
Пример конфигурации:
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: "us-west-002"
DISCOURSE_S3_INSTALL_CORS_RULE: false
DISCOURSE_S3_CONFIGURE_TOMBSTONE_POLICY: false
DISCOURSE_S3_ENDPOINT: https://s3.us-west-002.backblazeb2.com
DISCOURSE_S3_ACCESS_KEY_ID: myaccesskey
DISCOURSE_S3_SECRET_ACCESS_KEY: mysecretkey
DISCOURSE_S3_CDN_URL: https://falcoland-files-cdn.falco.dev
DISCOURSE_S3_BUCKET: falcoland-files
DISCOURSE_S3_BACKUP_BUCKET: falcoland-files/backup
DISCOURSE_BACKUP_LOCATION: s3
Примечание: При первоначальной миграции в B2 вы можете столкнуться с лимитом в 2500 бесплатных ежедневных транзакций класса C. Вам нужно будет добавить способ оплаты, чтобы снять ограничения.
MinIO Storage Server
Есть несколько оговорок и требований, которые необходимо выполнить перед использованием сервера хранилища MinIO в качестве альтернативы S3:
- У вас есть полностью настроенный экземпляр сервера MinIO.
- В конфигурации MinIO включена поддержка доменов для URL-адресов бакетов, управляемых доменом. Это обязательное требование настройки для MinIO и Discourse, так как MinIO всё ещё поддерживает устаревшие «путь»-стили S3, которые больше не поддерживаются в Discourse.
- Конфигурация DNS для MinIO настроена правильно, чтобы поддомены бакетов корректно разрешались на сервер MinIO, и сервер MinIO настроен с базовым доменом (в данном случае
minio.example.com). - Бакет
discourse-dataсуществует на сервере MinIO и имеет установленную политику «public». - Ваш URL CDN S3 указывает на правильно настроенный CDN, обслуживающий бакет и кэширующий запросы, как указано ранее в этом документе.
- Ваши CDN настроены на использование заголовка «Host» основного URL S3 — например,
discourse-data.minio.example.comпри извлечении данных — в противном случае это может вызвать проблемы CORB.
При условии выполнения вышеуказанных оговорок и предварительных требований пример конфигурации будет выглядеть примерно так:
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: anything
DISCOURSE_S3_ENDPOINT: https://minio.example.com
DISCOURSE_S3_ACCESS_KEY_ID: myaccesskey
DISCOURSE_S3_SECRET_ACCESS_KEY: mysecretkey
DISCOURSE_S3_CDN_URL: https://discourse-data-cdn.example.com
DISCOURSE_S3_BUCKET: discourse-data
DISCOURSE_S3_BACKUP_BUCKET: discourse-backups
DISCOURSE_BACKUP_LOCATION: s3
DISCOURSE_S3_INSTALL_CORS_RULE: false
CORS всё ещё будет включен на MinIO, даже если правило не устанавливается сборщиком приложения — по умолчанию, как кажется, CORS включен для всех HTTP-методов в MinIO, и в результате MinIO не поддерживает BucketCORS (S3 API).
Azure Blob Storage с Flexify.IO
Azure Blob Storage не является сервисом, совместимым с S3, поэтому его нельзя использовать с Discourse. Существует плагин, но он неработоспособен.
Самый простой способ предоставить интерфейс, совместимый с S3, для Azure Blob Storage, — это добавить сервер Flexify.IO, который преобразует протокол Azure Storage в S3.
На момент написания этой статьи сервис бесплатен на Azure, и вам нужен только очень базовый (дешевый) уровень ВМ для начала работы. Однако это требует некоторой настройки.
- В портале Azure создайте новый ресурс
Flexify.IO - Amazon S3 API for Azure Blob Storage. - Для легкой нагрузки минимальная конфигурация ВМ, похоже, работает отлично. Вы можете принять большинство настроек по умолчанию. Не забудьте сохранить файл ключа PEM при создании ВМ.
- Перейдите по ссылке на ВМ Flexify.IO и войдите в систему. Следуйте инструкциям, настроив поставщика данных Azure Blob Storage и сгенерированную конечную точку S3. Убедитесь, что настройка конечной точки
Public read access to all objects in virtual bucketsустановлена в true. Скопируйте URL конечной точки S3 и ключи. - Нажмите New Virtual Bucket и создайте виртуальный бакет. Он может иметь то же имя, что и контейнер Azure Blob Storage, или другое имя. Свяжите любой контейнер(ы) для объединения в этот виртуальный бакет. Этот виртуальный бакет используется для предоставления общедоступного бакета через S3.
- По умолчанию Flexify.IO устанавливает самоподписанный SSL-сертификат, тогда как конечная точка S3 требует HTTPS. Подключитесь к ВМ по SSH с помощью файла ключа (имя пользователя по умолчанию
azureuser) и замените следующие файлы правильными:
-
/etc/flexify/ssl/cert.pem— замените файлом сертификата (кодировка PEM) -
/etc/flexify/ssl/key.pem— замените файлом приватного ключа (кодировка PKCS#8 PEM, это тот, который начинается сBEGIN PRIVATE KEY, а неBEGIN RSA PRIVATE KEY, который является PKCS#1)Эти файлы принадлежат root, поэтому вам придется использовать
sudoдля их замены. Лучше всего убедиться, что заменяемые файлы имеют те же владельца и права доступа, что и оригиналы, то естьroot:rootи права600.
- По умолчанию Flexify.IO создает сервис S3 корневого уровня с несколькими бакетами. Discourse требует поддержки поддоменов для бакетов. Перейдите по адресу:
https://<ваш-ip-flexify-io>/flexify-io/manage/admin/engines/configs/1, что откроет скрытую страницу конфигурации! - Укажите базовый домен S3 (например,
s3.mydomain.com) в полеEndpoint hostname, которое по умолчанию должно быть пустым. Нажмите Save, чтобы сохранить настройку. - Перезапустите ВМ Flexify.IO в портале Azure.
- В вашей DNS настройте сопоставление
s3.mydomain.comи*.s3.mydomain.comс IP-адресом ВМ Flexify.IO. - В Discourse установите следующие параметры на странице администратора (да, нет необходимости настраивать их в
app.yml):
use s3: true
s3 region: anything
s3 endpoint: https://s3.mydomain.com
s3 access key: myaccesskey
s3 secret assess key: mysecret key
s3 cdn url: https://<azure-blob-account>.blob.core.windows.net/<container>
s3 bucket: <virtual bucket>
s3 backup bucket: <backup bucket> (подойдет любой контейнер, так как он не требует общедоступного чтения, и Flexify.IO автоматически предоставит к ним доступ)
backup location: s3
Использование одного и того же бакета для продакшена и стейджинга не рекомендуется. Если вы всё же решите это сделать, примите меры, чтобы ваш сайт стейджинга не удалил ресурсы продакшена (установите s3 disable cleanup как минимум и следите за удалением резервных копий продакшена).
Wasabi
@pfaffman пробовал Wasabi для резервного копирования, но оно казалось нестабильным и молчаливо терпело неудачу, оставляя резервные копии на жестком диске и в конечном итоге заполняя диск. Ни Wasabi, ни meta не могли дать подсказок, поэтому я не рекомендую это, хотя ваш опыт может отличаться. @pfaffman теперь довольно уверен, что эта проблема была вызвана тем, что резервное копирование и автоматические перезагрузки каким-то образом планировались одновременно; использовалось только для резервного копирования, но казалось, что работает нормально. Если кто-то захочет попробовать и сообщить здесь, это должно работать, по крайней мере, для резервного копирования.
Oracle Cloud
Oracle Cloud не поддерживает доступ к бакетам в стиле виртуального хостинга и не будет работать.
Cloudflare R2
Для настройки Cloudflare R2 вам необходимо настроить соответствующие параметры в панели управления Cloudflare в разделе R2 Object Storage.
В зависимости от ваших потребностей (загрузки, резервные копии или оба варианта), вот соответствующие настройки, которые нужно добавить в файл app.yml или в Admin - All site settings (поиск по S3):
DISCOURSE_ENABLE_S3_UPLOADS: true
DISCOURSE_S3_REGION: auto
DISCOURSE_S3_ENDPOINT: https://<your-account-id>.r2.cloudflarestorage.com
DISCOURSE_S3_ACCESS_KEY_ID: "xxx"
DISCOURSE_S3_SECRET_ACCESS_KEY: "xxx"
DISCOURSE_S3_UPLOAD_BUCKET: your-upload-bucket-name
DISCOURSE_S3_CDN_URL: https://uploads.yourdomain.com
# DISCOURSE_S3_USE_CDN_URL_FOR_ALL_UPLOADS: true
DISCOURSE_ENABLE_DIRECT_S3_UPLOADS: true
DISCOURSE_S3_USE_ACLS: false
DISCOURSE_BACKUP_LOCATION: s3
DISCOURSE_S3_BACKUP_BUCKET: your-backup-bucket-name
Если вы не хотите редактировать app.yml, вы можете сделать это в интерфейсе администратора:
«Admin → All site settings» (поиск по S3):
- Enable S3 uploads =
true - Enable direct S3 uploads =
true - S3 access key ID =
"xxx" - S3 secret access key =
"xxx" - S3 region =
any - S3 upload bucket =
your upload bucket name - S3 endpoint =
https://<your-account-id>.r2.cloudflarestorage.com - S3 CDN URL =
https://uploads.yourdomain.com - S3 use ACLs =
false(отключите это!) - S3 backup bucket =
your backup bucket name - Backup location =
S3
Примечания:
-
Разрешения токена API: Поскольку в Discourse есть только одно поле для учетных данных, токен API, который вы генерируете в Cloudflare, должен иметь разрешение на доступ как к бакету загрузок, так и к бакету резервных копий. При создании токена выберите «Apply to all buckets» или используйте «Apply to specific buckets» и убедитесь, что оба отмечены. Также убедитесь, что при создании ключа API вы отметили
Object Read & Write(по умолчанию толькоObject Read only). -
При копировании URL конечной точки из Cloudflare он может добавить имя бакета к URL — вам следует удалить имя бакета из конца строки в вашем файле
.yml, если оно было вставлено. -
Раскомментируйте
# DISCOURSE_S3_USE_CDN_URL_FOR_ALL_UPLOADS: true, если вы хотите использовать свой бакет загрузок R2 для всех загрузок, включая файлыPDFиZIP. (Обратите внимание, что это сделает все загруженные файлы общедоступными по прямой ссылке) -
Если вы включили
DISCOURSE_ENABLE_DIRECT_S3_UPLOADS(true), вы должны отключитьDISCOURSE_S3_USE_ACLS(false). Это связано с тем, что Cloudflare R2 использует разрешения на уровне бакетов; ваш бакет загрузок должен быть общедоступным, а бакет резервных копий — приватным. Для загрузок в Cloudflare R2 вам НЕ НУЖНО настраивать задачи rake для правил CORS или писать IAM json, так как вы настроите это в панели управления Cloudflare при настройке разрешений бакета. Токен Cloudflare «Object Read & Write» автоматически предоставляет разрешения на многокомпонентную загрузку, и вставка следующего правила CORS напрямую в настройки бакета загрузок R2 в панели управления Cloudflare в разделеCORS Policyзаменяет необходимость в задаче rake.
[
{
"AllowedOrigins": [
"https://forum.yourdomain.com"
],
"AllowedMethods": [
"GET",
"PUT",
"POST",
"DELETE",
"HEAD"
],
"AllowedHeaders": [
"*"
],
"ExposeHeaders": [
"ETag"
],
"MaxAgeSeconds": 3000
}
]
Contabo
@tuxed пытался заставить Contabo Object Storage работать для загрузок, совместимых с S3. Похоже, что при загрузке он добавляет префикс имени репозитория в URL, и ему не удалось заставить это работать.
Безопасные загрузки
Безопасные загрузки поддерживаются только для AWS S3. Если ваша команда rake uploads:migrate_to_s3 не выполняется, вы должны ввести следующие команды, чтобы сначала подсчитать, а затем пометить как небезопасные те загрузки, которые, как вы знаете, не требуют безопасности (в этом случае вам нужно будет использовать AWS S3).
./launcher enter app
rails c
Upload.where(secure: true).count
Upload.where(secure: true).update_all(secure:false)