Cloudflare R2 存储桶可用于存储 Discourse 社群的静态资源(如图片和 GIF),但不能用于存储社群备份!
简介:
Cloudflare R2 对象存储可用作 Amazon S3 的替代方案,用于存储 Discourse 论坛的上传文件。以下步骤概述了如何进行配置。
配置步骤:
- 启用 S3 上传: 在 Discourse 设置中勾选启用 S3 上传的复选框。
- S3 访问密钥 ID: 输入 R2 存储桶的 API 密钥 ID。这是创建存储桶 API 令牌时提供的 ID。
- S3 密钥: 输入创建授予对存储桶访问权限的 API 令牌时提供的密钥。重要提示: 此密钥仅显示一次,请务必安全备份。
- S3 区域: 可以输入任何区域,对于 R2 来说无关紧要。
- S3 上传存储桶: 输入 R2 存储桶的名称。
- S3 端点: 输入 R2 存储桶的 S3 API 链接,格式为
https://xxxxxx.com。请参阅 Cloudflare R2 控制面板查找此链接。
- S3 CDN URL: 输入存储桶的公共 R2.dev 存储桶 URL。此链接也将在 Cloudflare R2 控制面板中找到。
完成:
配置完这些设置后,您的 Discourse 论坛将设置为使用 Cloudflare R2 进行存储。
免费套餐信息:
Cloudflare 的 R2 服务提供免费套餐,包括每月 10 GB 存储空间、100 万次上传和 100 万次读取操作。
5 个赞
pfaffman
(Jay Pfaffman)
2
我建议您遵循为上传配置 S3 兼容对象存储提供商中的示例,并将设置放在 yml 文件中,而不是数据库中。
感谢您的反馈。我之前仔细阅读了该指南,并且我认为关于 Cloudflare R2 的建议是不正确的。文章建议 Discourse 社区不支持 Cloudflare R2 存储桶。然而,实际上 Cloudflare R2 与 S3 高度兼容,并且可以完美地处理 Discourse 社区的图片和文件上传和下载。这已经通过我在我的社区 (starorigin.net) 上的实际应用得到了验证。
1 个赞
pfaffman
(Jay Pfaffman)
4
我怀疑文章写的时候确实是这样。
将 S3 设置放在 yml 文件中比通过用户界面配置并将它们存储在数据库中要好得多。您是否尝试过将数据库恢复到新服务器?
设置好推荐的配置后,您可以编辑该主题或发表评论并请其他人来编辑。
1 个赞
你说得对,我使用 Cloudflare R2 存储桶来存储社区的图片、GIF 和其他资源。这大大减轻了社区服务器的负载,并加快了页面加载速度。
我还没有为我的社区设置自动备份以存储在 Cloudflare R2 存储桶中,因为 Cloudflare R2 存储桶不支持存储压缩文件。但是,Cloudflare R2 存储可以存储社区的 PDF、图片、GIF 和其他静态资源,这也非常好。
pfaffman
(Jay Pfaffman)
6
有趣。我以为我以前用 R2 做过备份。但也许我记错了。
你仍然可以遵循推荐的说明,并注意不要把备份放在那里。
谢谢提醒,我会重点关注这部分。
Cloudflare R2 存储桶可用于存储 Discourse 社区的静态资源(如图片和 GIF),但不能用于存储社区备份!
Eviepayne
(vladtheimplier)
8
为了更新此帖子,我需要包含一些在 Cloudflare 为我工作之前必须解决的陷阱。
1. 区域
事实并非如此,我必须使用“auto”或我选择的区域,“auto”更容易,所以请使用“auto”。
如果您需要知道可以使用哪些选项,请尝试使用任意随机字符串作为您的区域,然后:
sudo -E -u discourse bundle exec rake s3:upload_assets
如果您使用 nixos
sudo discourse-rake s3:upload_assets
这将输出一个错误,其中包含您的有效选项。
2. API 权限
同样重要的是要知道,限制性的 API 令牌不起作用。您必须使用 Admin Read & Write
Object Read & Write 不起作用。
3 个赞
运行 sudo -E -u discourse bundle exec rake s3:upload_assets 时出错 @Eviepayne
Eviepayne
(vladtheimplier)
10
将区域设置为自动。
您可能还需要设置:
DISCOURSE_S3_INSTALL_CORS_RULE: false
我已完成以上两项操作并重新构建了 app.yml:
## S3 配置
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: auto
DISCOURSE_S3_ACCESS_KEY_ID: XXX
DISCOURSE_S3_SECRET_ACCESS_KEY: XXX
DISCOURSE_S3_CDN_URL: https://pub-XXX.r2.dev
DISCOURSE_S3_ENDPOINT: https://XXX.r2.cloudflarestorage.com/XXX
DISCOURSE_S3_BUCKET: XXX
DISCOURSE_S3_INSTALL_CORS_RULE: false
我还确认了 API 密钥是账户 API 密钥,而不是仅限于存储桶的密钥(如帖子中所述)。此外,我的 Discourse 实例显示如下:
运行 sudo -E -u discourse bundle exec rake s3:upload_assets 后显示:
`/root` 不可写。
Bundler 将暂时使用 `/tmp/bundler20250410-2363-zj2g6x2363` 作为您的主目录。
正在安装 CORS 规则...
跳过
rake 中止!
Seahorse::Client::NetworkingError: 响应正文为空或不完整 (Seahorse::Client::NetworkingError)
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/seahorse/client/plugins/raise_response_errors.rb:17:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-s3-1.182.0/lib/aws-sdk-s3/plugins/sse_cpk.rb:24:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-s3-1.182.0/lib/aws-sdk-s3/plugins/dualstack.rb:21:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-s3-1.182.0/lib/aws-sdk-s3/plugins/accelerate.rb:43:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/plugins/checksum_algorithm.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/plugins/jsonvalue_converter.rb:16:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/plugins/invocation_id.rb:16:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/plugins/idempotency_token.rb:19:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/plugins/param_converter.rb:26:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/seahorse/client/plugins/request_callback.rb:89:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/plugins/response_paging.rb:12:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/seahorse/client/plugins/response_target.rb:24:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/plugins/telemetry.rb:39:in `block in call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/telemetry/no_op.rb:29:in `in_span'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/plugins/telemetry.rb:53:in `span_wrapper'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/plugins/telemetry.rb:39:in `call'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/seahorse/client/request.rb:72:in `send_request'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-s3-1.182.0/lib/aws-sdk-s3/client.rb:12654:in `list_objects_v2'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-s3-1.182.0/lib/aws-sdk-s3/bucket.rb:1513:in `block (2 levels) in objects'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/plugins/user_agent.rb:69:in `metric'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-s3-1.182.0/lib/aws-sdk-s3/bucket.rb:1512:in `block in objects'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/resources/collection.rb:101:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/resources/collection.rb:101:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/resources/collection.rb:101:in `block in non_empty_batches'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/resources/collection.rb:52:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/resources/collection.rb:52:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/resources/collection.rb:52:in `block in each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/resources/collection.rb:58:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/resources/collection.rb:58:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.219.0/lib/aws-sdk-core/resources/collection.rb:58:in `each'
/var/www/discourse/lib/tasks/s3.rake:14:in `map'
/var/www/discourse/lib/tasks/s3.rake:14:in `existing_assets'
/var/www/discourse/lib/tasks/s3.rake:36:in `upload'
/var/www/discourse/lib/tasks/s3.rake:197:in `block (2 levels) in <main>'
/var/www/discourse/lib/tasks/s3.rake:197:in `each'
/var/www/discourse/lib/tasks/s3.rake:197:in `block in <main>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/exe/rake:27:in `<top (required)>'
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'
Tasks: TOP => s3:upload_assets
(运行任务时显示 --trace 以查看完整跟踪)
Eviepayne
(vladtheimplier)
12
我认为您可能需要从端点中删除存储桶名称。
应删除末尾的 /xxx,使其仅为 .com。
正在重建并重新运行命令,感谢您的帮助!
我的 app.yml 现在如下所示:
## S3 配置
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: auto
DISCOURSE_S3_ACCESS_KEY_ID: XXX
DISCOURSE_S3_SECRET_ACCESS_KEY: XXX
DISCOURSE_S3_CDN_URL: https://pub-XXX.r2.dev
DISCOURSE_S3_ENDPOINT: https://XXX.r2.cloudflarestorage.com
DISCOURSE_S3_BUCKET: XXX
DISCOURSE_S3_INSTALL_CORS_RULE: false
Eviepayne
(vladtheimplier)
14
我认为以上都正确。
请确保 CDN_URL(https://pub-xxx.r2.dev)具有公共读取权限,以便匿名用户可以查看资源。
您可以通过浏览器的开发者工具了解情况。如果权限设置错误,您将在网络选项卡中看到大量 403 错误和红色请求。
Eviepayne
(vladtheimplier)
16
有一种方法可以做到这一点,但这并非推荐做法,并且您会遇到问题。
假设您已经拥有自己的域名,并且 Cloudflare 已经是您的 DNS:
Cloudflare 将自动代理该域并为其进行缓存。
然后,您可以将 CDN_URL 更改为该自定义域名。
Eviepayne
(vladtheimplier)
18
在 S3 存储桶设置内部有一个公共访问设置。
为它设置一个唯一的子域名。(Cloudflare 会自动为你创建 DNS 记录,同时进行代理和缓存)
我想我搞定了?
您是否也成功将备份配置到了 Cloudflare R2,并且(假设可以备份到 Cloudflare R2)是否有可能同时进行本地备份和 Cloudflare R2 备份?
另外,上传所有资源的脚本是否意味着它会删除本地资源(以释放存储空间)?还是我需要单独执行此操作?
感谢您花时间帮助我 
Eviepayne
(vladtheimplier)
20
我个人还没试过。
我的论坛属于“不受支持”类别,因为我的数据库是外部的,并且我的备份策略与论坛使用的 pg_dumps 不同。
据我所知,备份在 Cloudflare 上不起作用,但没有什么能阻止你尝试一下。
1 个赞