如何为discourse社区设置cloudflare R2存储桶?

:information_source: 本主题阐述如何配置一些常见的 S3 兼容对象存储服务提供商(S3 克隆)。关于 Amazon AWS S3 的配置详情,请参阅 https://meta.discourse.org/t/setting-up-file-and-image-uploads-to-s3/7229,该配置是官方支持的,Discourse 内部也将其用于我们的托管服务。

提供商 服务名称 是否与 Discourse 兼容?
Amazon AWS S3
Digital Ocean Spaces
Linode 对象存储
Google Cloud 存储
Scaleway 对象存储
Vultr 对象存储
BackBlaze 云存储 是*
自托管 MinIO
Azure Blob Storage Flexify.IO
Oracle Cloud 对象存储 [1]
Wasabi 对象存储 可能
Cloudflare R2 支持
Contabo 对象存储

如果您成功使用了其他服务,请将其添加到此维基中。

配置

为了将 Discourse 静态资源存储在您的对象存储中,请在 app.ymlhooks 部分添加以下配置:

  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 来服务存储在存储桶中的内容。我在测试中使用了 StackPath CDN,除了需要在其配置中设置 Dynamic Caching By Header: Accept-Encoding 之外,它工作正常。

DISCOURSE_CDN_URL 是一个指向您的 Discourse 主机名并缓存请求的 CDN。它主要用于可拉取的资源:CSS 和其他主题资源。

DISCOURSE_S3_CDN_URL 是一个指向您的对象存储桶并缓存请求的 CDN。它主要用于可推送的资源:JS、图像和用户上传。

我们建议这两者不同,并建议管理员同时设置两者。

不使用 CDN(或将存储桶 URL 作为 CDN URL 输入)可能会导致问题,并且不受支持。

在以下示例中,https://falcoland-files-cdn.falco.dev 是一个配置为服务存储桶下文件的 CDN。在我的示例中,存储桶名称设置为 falcoland-files

建议在 app.yml 的环境变量中配置这些设置,因为 CDCK 在其基础设施中就是这样做的,因此经过了充分的测试。此外,上传资源的任务发生在资源编译之后,而资源编译发生在重建过程中。如果您想从一开始就启动一个与对象存储正常工作的 Discourse,则需要设置环境变量,以便在站点启动之前上传资源。

从下面的列表中选择您的提供商,并将这些设置添加到 app.yml 文件的 env 部分,并根据需要调整值:

AWS S3

这是我们官方支持并在内部使用的服务。他们的 CDN 产品 Cloudfront 也可用于前端存储桶文件。有关如何正确配置权限,请参阅 https://meta.discourse.org/t/setting-up-file-and-image-uploads-to-s3/7229。

  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 的产品很好,开箱即用。启用“限制文件列表”是可以的。唯一的问题是他们的 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 对象存储

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 存储

列出文件已损坏,因此您需要一个额外的 ENV 来跳过该操作,以便资源可以工作。此外,跳过 CORS 并手动配置它。

:warning: 由于您无法列出文件,因此您将无法列出备份,并且自动备份将失败,我们不建议将其用于备份。但是,有人建议,如果您将角色从 Storage Legacy Object Owner 更改为 Storage Legacy Bucket Owner,则备份可以正常工作。有关 Google Cloud 的具体讨论,请参阅此主题

有一个第三方插件可以更好地集成,网址为 https://meta.discourse.org/t/discourse-gcs-helper/247705。

配置示例:

  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 对象存储

Scaleway 的产品也非常好,并且在大多数情况下一切正常。

:warning: Scaleway 多部分上传仅支持最多 1,000 个部分。这与 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 对象存储

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 云存储

您需要跳过 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 存储服务器

在将 MinIO 存储服务器用作 S3 的替代方案之前,您需要确保满足一些注意事项和要求:

  1. 您有一个完全配置的 MinIO 服务器实例
  2. 您在 MinIO 配置中启用了域支持,用于域驱动的存储桶 URL。这是 MinIO 和 Discourse 的强制设置要求,因为 MinIO 仍然支持 Discourse 中不再支持的旧版 S3“路径”样式。
  3. 您已为 MinIO 正确设置 DNS 配置,以便存储桶子域正确解析到 MinIO 服务器,并且 MinIO 服务器配置了基本域(在本例中为 minio.example.com
  4. 存储桶 discourse-data 存在于 MinIO 服务器上,并且对其设置了“公共”策略
  5. 您的 S3 CDN URL 指向一个正确配置的 CDN,该 CDN 指向存储桶并缓存请求,如本文档前面所述。
  6. 您的 CDN 配置为实际使用核心 S3 URL 的“Host”标头 - 例如,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 在 MinIO 中的所有 HTTP 动词上启用,并且 MinIO 不支持 BucketCORS (S3 API)。

Azure Blob Storage 与 Flexify.IO

Azure Blob Storage 不是 S3 兼容的服务,因此不能与 Discourse 一起使用。有一个插件,但它已损坏。

Azure Blob Storage 公开 S3 兼容接口的最简单方法是添加一个 Flexify.IO 服务器,该服务器将 Azure 存储协议 转换 为 S3。

在撰写本文时,该服务在 Azure 上是免费的,您只需要一个非常基本的(便宜的)VM 层即可开始运行它。但是,它确实需要一些设置。

  1. 在 Azure 门户中,创建一个新的 Flexify.IO - Amazon S3 API for Azure Blob Storage 资源。
  2. 对于轻度使用,最小 VM 配置似乎可以正常工作。您可以接受大多数默认配置。创建 VM 时,请记住保存 PEM 密钥文件。
  3. 浏览到 Flexify.IO VM 链接,然后进入系统。按照说明设置 Azure Blob Storage 数据提供程序和生成的 S3 端点。确保端点配置设置 Public read access to all objects in virtual buckets 为 true。复制 S3 端点 URL 和密钥。
  4. New Virtual Bucket 并创建一个虚拟存储桶。它可以与您的 Azure Blob Storage 容器的名称相同,也可以是不同的名称。链接要合并到此虚拟存储桶中的任何容器。此虚拟存储桶用于通过 S3 公开可公开读取的存储桶。
  5. 默认情况下,Flexify.IO 安装自签名 SSL 证书,而 S3 端点需要 HTTPS。使用密钥文件(默认用户名为 azureuser)SSH 进入 VM,并将以下文件替换为正确的文件:
  • /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:root600 权限。

  1. 默认情况下,Flexify.IO 创建一个具有多个存储桶的根级 S3 服务。Discourse 需要存储桶的 子域 支持。转到:<your Flexify.IO VM IP>/flexify-io/manage/admin/engines/configs/1,这将打开一个 隐藏的 配置页面!
  2. Endpoint hostname 字段中指定 S3 基本域(假设它是 s3.mydomain.com),该字段默认应为空白。按 Save 保存设置。
  3. 在 Azure 门户中重新启动 Flexify.IO VM。
  4. 在您的 DNS 中,将 s3.mydomain.com*.s3.mydomain.com 映射到 Flexify.IO VM IP。
  5. 在 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

Cloudflare 的产品不兼容。在测试中,@fearlessfrog 向 Cloudflare 提交了一张工单,他们在 2022 年 12 月表示:

Contabo

@tuxed 尝试使 Contabo 对象存储用于 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)

  1. Oracle Cloud 不支持对存储桶的虚拟主机式访问,并且无法正常工作↩︎

截屏2025-01-27 18.45.58
验证图片上传到存储桶