您好,
我正在尝试设置 S3 上传,似乎上传工作正常,但 GET 请求因奇怪的原因失败。看起来 discourse 在上传对象的 URI 中添加了“.cn”
在我的 S3 存储桶中上传图片后,公共 URL 是:
https://hobig...bucket-eu.s3.eu-central-1.amazonaws.com/original/1X/5e894113...48918.jpeg
但当我检查浏览器时,我的 discourse 论坛正在尝试加载(请注意 .cn):
https://hobig...bucket-eu.s3.eu-central-1.amazonaws.com.cn/original/1X/5e894113...48918.jpeg
有人知道为什么会这样吗?
这是我的管理员设置:
pfaffman
(Jay Pfaffman)
2
您应该遵循 为上传配置 S3 兼容对象存储提供商 和/或 Set up file and image uploads to S3 中的说明,并将这些设置放在您的 yml 文件中,而不是放在数据库/用户体验中。
您不需要为 AWS 配置端点。您确实需要配置一个 CDN。
1 个赞
您好 @pfaffman,
您似乎无意中重复粘贴了同一个指南。
当您提到“yml 文件中的设置”时,您能否澄清您指的是哪个 YAML 文件?您是否在谈论位于 /var/discourse/containers 文件夹中的 app.yml 文件?
此外,如果我直接通过 YAML 文件配置我的 S3/CloudFront 集成,这些设置会覆盖 Discourse 管理部分中的配置吗?
谢谢!
pfaffman
(Jay Pfaffman)
4
抱歉。其中一个应该是 https://meta.discourse.org/t/set-up-file-and-image-uploads-to-s3/7229。
请参阅有关如何配置 S3 的链接主题,但是的,app.yml 是您想要更改的文件(因为您没有提到 web_only.yml)
是的。在 YML 文件中输入它们会将它们从用户界面中隐藏。
您好 @pfaffman,
我已经设置好了 S3 存储桶、CloudFront,并将 CloudFront 的源设置为我的 S3 存储桶。这是我当前的 app.yml 配置:
ENV:
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: eu-central-1
DISCOURSE_S3_ACCESS_KEY_ID: AKIAWPLPUxxxxxx
DISCOURSE_S3_SECRET_ACCESS_KEY: PaXQu7pKxxxx
DISCOURSE_S3_CDN_URL: https://dsuxxxhrz2qn.cloudfront.net
DISCOURSE_S3_BUCKET: hobigxxxxbucket-eu
使用 ./launcher rebuild app 重建应用程序后,当我访问网站时,它只会显示加载器而什么都不加载。检查网络选项卡后,我发现它无法获取预编译的静态资源(主要是 .js),我猜测是因为它们不在我的 S3 存储桶中。您可以在此处查看:forum.hobiguru.com。
我还尝试运行迁移 rake 任务,但徒劳无功:
root@ubuntu-s-1vcpu-1gb-fra1-01-app:/var/www/discourse# rake uploads:migrate_to_s3 --trace
** Invoke uploads:migrate_to_s3 (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute uploads:migrate_to_s3
请注意,迁移到 S3 目前是不可逆的!
[CTRL+c] 取消,[ENTER] 继续
正在为 'default' 迁移上传到 S3...
一些上传未迁移到新方案。运行迁移,这可能需要一段时间...
rake aborted!
FileStore::ToS3MigrationError: Some uploads could not be migrated to the new scheme. You need to fix this manually. (FileStore::ToS3MigrationError)
/var/www/discourse/lib/file_store/to_s3_migration.rb:156:in `migrate_to_s3'
/var/www/discourse/lib/file_store/to_s3_migration.rb:59:in `migrate'
/var/www/discourse/lib/tasks/uploads.rake:126:in `migrate_to_s3'
/var/www/discourse/lib/tasks/uploads.rake:106:in `block in migrate_to_s3_all_sites'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management/null_instance.rb:49:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management/null_instance.rb:36:in `each_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rails_multisite-6.1.0/lib/rails_multisite/connection_management.rb:21:in `each_connection'
/var/www/discourse/lib/tasks/uploads.rake:104:in `migrate_to_s3_all_sites'
/var/www/discourse/lib/tasks/uploads.rake:100:in `block in <main>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `block in execute'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:281:in `execute'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:219:in `block in invoke_with_call_chain'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:199:in `synchronize'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:199:in `invoke_with_call_chain'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/task.rb:188:in `invoke'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:188:in `invoke_task'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `block (2 levels) in top_level'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:138:in `block in top_level'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:147:in `run_with_threads'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:132:in `top_level'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:83:in `block in run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:214:in `standard_exception_handling'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.2.1/lib/rake/application.rb:80:in `run'
bin/rake:13:in `<top (required)>'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli/exec.rb:58:in `load'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli/exec.rb:58:in `kernel_load'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli/exec.rb:23:in `run'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli.rb:455:in `exec'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor/command.rb:28:in `run'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor.rb:527:in `dispatch'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli.rb:35:in `dispatch'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/vendor/thor/lib/thor/base.rb:584:in `start'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/cli.rb:29:in `start'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/exe/bundle:28:in `block in <top (required)>'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.18/exe/bundle:20:in `<top (required)>'
/usr/local/bin/bundle:25:in `load'
我最初的目的是只使用 S3 来存储用户上传的文件,并且我添加了 CDN 来处理这个问题。但是,现在我遇到了一个新问题——我的应用程序的静态资源也通过 CDN 提供服务,这并非我的本意。 
有没有办法在应用程序启动时将所有静态资源上传到 S3 存储桶,然后通过 CDN 提供服务,或者有没有办法只通过 CDN 提供用户上传的文件,或者是否有更好的解决方案?
也许我还是忽略了显而易见的东西?不知道
感谢您的帮助!
pfaffman
(Jay Pfaffman)
6
我怀疑那是因为你没有遵循说明。
是的。我明白。这是可能的,但你无法实现。这是推荐的方式;它有详细的文档,而且有数百人都是这样做的。
1 个赞
抱歉,你说得对,我漏掉了那部分。我已将以下内容添加到我的 app.yml 中,现在论坛可以正确加载了:
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
尽管如此,用户上传仍然无法正常工作。上传到 S3 存储桶(正确地)后,图像的访问方式如下:
//my-bucket-eu.my-bucket-eu/original/1X/7f242572bdb45b65ded727c13366fe490541358f.jpeg
这显然不是有效的 S3 或 CDN 路径。
在你提到的指南中,有这样一段似乎很相关:
DISCOURSE_CDN_URL 是一个指向你的 Discourse 主机名并缓存请求的 CDN。它主要用于可拉取的资源:CSS 和其他主题资源。
DISCOURSE_S3_CDN_URL 是一个指向你的对象存储桶并缓存请求的 CDN。它主要用于可推送的资源:JS、图像和用户上传。
我们建议将它们设置为不同的值,并由管理员进行设置。
但是,我不确定 DISCOURSE_CDN_URL 应该设置为多少?我应该将其设置为与 DISCOURSE_S3_CDN_URL: https://dsxxxxx2qn.cloudfront.net 相同的值,还是创建一个单独的 CDN 实例?
又或者,这可能是完全不同的问题 
非常感谢你的所有帮助!
Jagster
(Jakke Lehtonen)
8
您需要在 AWS 端配置 CDN 并使用您想要的域名。另外,还需要配置 DNS。
但为什么呢?实际上没有人会看到那个 URL。
1 个赞
嗨 Jake,我不确定我是否正确理解了你的意思。你能详细说明一下吗?
你的意思是不是,我应该将我的 forum.hobiguru.com 域名设置为 CDN 的源站,而不是将 S3 存储桶设置为源站?如果是这样,我认为这不会有任何改变,因为是 discourse 论坛生成了那些指向无效位置的 URL,例如 //my-bucket-eu.my-bucket-eu/original/1X/7f242572bdb45b65ded727c13366fe490541358f.jpeg
我已经添加了 DISCOURSE_CDN_URL: https://dsuxxxhrz2qn.cloudfront.net,现在正在等待应用程序重建 
更新:不行,这也没起作用 :/\
我真的很感谢你的帮助。
谢谢你
Jagster
(Jakke Lehtonen)
10
您不能仅在 app.yml 中命名子域。没有人可以在没有正确 DNS 信息的情况下使用它。而且,由于您的文件是从 AWS 提供的,如果您想使用 CDN,也必须配置那边的设置。
但再说一次。用户可以看到 Discourse 的 URL,如果他们想看的话。除了管理员,很少有人会做其他事情。用户实际上看不到媒体或其他静态文件的 URL。
所以,我的观点是,如果您不想使用 CDN,您就是在浪费时间。如果您的受众遍布全球,并且其中一些人连接状况不佳,那么使用 CDN 可能很明智。
我住在芬兰。如果世界上另一个地方(澳大利亚)的网站使用 CDN(来自离我 1000 公里外的服务器),我不会得到任何实际的好处。真正的瓶颈在于网站的构建方式,例如是否使用了大量不必要的 PHP 调用而没有足够的资源。
但基本上,您不能在不至少在 DNS 中放置 cdn 的情况下使用 cdn.example.tld 这个 URL。
您好 @Jagster
实际上,我根本不想使用 CDN——我只想将所有用户上传都存储在 S3 中,并直接从那里提供服务,尽管 CloudFront 确实比直接使用 S3 是一个更好的解决方案。
我的问题出现在我尝试设置 S3(特别是用于提供资源,而不是上传)时,@pfaffman 建议我遵循 为上传配置 S3 兼容对象存储提供商 指南并配置 CDN。
关于您的评论:
“您不能只在 app.yml 中命名一个子域。没有人可以在没有正确 DNS 信息的情况下使用它。并且因为您的文件是从 AWS 提供的,所以如果您想使用 CDN,您也必须配置那一边。”
抱歉,我不太明白您在这段话中的意思。您能详细说明或澄清一下吗?您是说我需要为我的 S3 存储桶配置 DNS 记录,还是说我需要在 AWS 端进行一些特定的调整?
提前感谢您的帮助!
大家好,
我想跟进之前的帖子,分享一下我已经取得的一些进展。
现在可以正常工作的功能
- 用户上传的内容现在可以正确地通过 CDN(CloudFront)从我的 S3 存储桶提供服务,这很棒!
但我仍然面临预编译资源的问题
预编译的资源仍然无法通过 CDN 正确提供服务。
当我将 DISCOURSE_CDN_URL 设置为 CloudFront URL(即 https://dsuqioxhrz2qn.cloudfront.net)时,预编译资源的 URL 变为:
问题在于,这些路径在我的 S3 存储桶中不存在。预编译的资源上传到 S3 的 /assets/* 文件夹下(例如,/assets/locales、/assets/plugins、/assets/scripts),但没有 /stylesheets/ 文件夹,因此加载这些 URL 会导致 403 Forbidden 错误。
但是,如果我将 DISCOURSE_CDN_URL 设置为 https://forum.hobiguru.com,那么我的论坛就可以正常工作,但资源是从服务器(例如 https://forum.hobiguru.com/)提供的,而不是从 CDN 提供的(例如 https://forum.hobiguru.com/stylesheets/admin_308d905aa5c03567866fec50e9a28d8721ab0463.css?__ws=forum.hobiguru.com)。
我的当前设置(供参考)是:
app.yaml
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: eu-central-1
DISCOURSE_S3_ACCESS_KEY_ID: AKIA......LQMB
DISCOURSE_S3_SECRET_ACCESS_KEY: PaXQu7pKN.....fJNY
DISCOURSE_S3_CDN_URL: https://dsuqioxhrz2qn.cloudfront.net # Ensure CDN URL points to CloudFront
DISCOURSE_CDN_URL: https://forum.hobigur.com # NOTICE THIS!
DISCOURSE_S3_BUCKET: hobiguru-s3-bucket-eu
以及预编译钩子:
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
似乎在预编译资源后,它们会以某种结构上传到 S3,但随后通过 CDN 加载时,对象的路径有点不对。