Unable to setup S3 bucket

Hi,

I’m trying to setup S3 uploads and it seems that the uploads are working correctly but the GET requests are failing for a weird reason. It seems that discourse is adding a “.cn” to the URI of the uploaded object

After uploading the image in my S3 bucket the public URL is:

https://hobig...bucket-eu.s3.eu-central-1.amazonaws.com/original/1X/5e894113...48918.jpeg

but when I inspect the browser my discourse forum is trying to load (notice the .cn)

https://hobig...bucket-eu.s3.eu-central-1.amazonaws.com.cn/original/1X/5e894113...48918.jpeg

Does anyone know why is this happening?

Here are my admin settings:

You should follow the instructions in Configure an S3 compatible object storage provider for uploads and/or Set up file and image uploads to S3 and put those settings in your yml file rather than in the database/UX.

You don’t need to configure an endpoint for AWS. You do want to configure a CDN.

1 Like

Hi @pfaffman,

It seems like you might have unintentionally pasted the same guide twice.

When you mention “settings in your yml file,” could you clarify which YAML file you’re referring to? Are you perhaps talking about the app.yml file located in the /var/discourse/containers folder?

Additionally, if I configure my S3/CloudFront integration directly through the YAML file, would those settings override what’s configured in the admin section of Discourse?

Thank you!

Sorry. One of those should have been Set up file and image uploads to S3.

See the linked topics that describe how to configure S3, but yes, the app.yml is what you want to change (since you didn’t mention web_only.yml)

Yes. Entering them in the YML file hides them from the UX.

Hi @pfaffman,

I have my S3 bucket, CloudFront setup, and CloudFront’s origin set to my S3 bucket. Here’s my current app.yml configuration:

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

After rebuilding the app with ./launcher rebuild app, when I visit the website, it just shows the loader without loading anything. Upon inspecting the network tab, I found that it can’t fetch the precompiled static assets (mostly .js), which I assume is because they aren’t in my S3 bucket. You can check it here: forum.hobiguru.com.

I also tried running the migration rake task, but to no avail:

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
Please note that migrating to S3 is currently not reversible!
[CTRL+c] to cancel, [ENTER] to continue
Migrating uploads to S3 for 'default'...
Some uploads were not migrated to the new scheme. Running the migration, this may take a while...
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'

My original intention was to use S3 only for storing user uploads, and I added the CDN just to handle that. However, now I’m facing a new problem — my app’s static assets are also being served through the CDN, which I didn’t intend. :confused:

Is there a way to upload all static assets on app launch to the S3 bucket and then have them served through the CDN, or maybe a way to only serve users’ uploads through CDN or is there a better solution for this?

Maybe I’m still missing something obvoius ? dunno
Thanks for your help!

I suspect that’s because you didn’t follow the instructions.

Yeah. I understand. That’s possible, but you couldn’t make that work. This is the recommended way; it’s well documented and hundreds of people do it this way.

1 Like

Sorry, you’re right I skipped that part exactly. I added the following into my app.yml and now it is loading the forum correctly:

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

Nonetheless, the user uploads are still not working correctly. After the upload into the S3 bucker (correctly) the image is served as:

//my-bucket-eu.my-bucket-eu/original/1X/7f242572bdb45b65ded727c13366fe490541358f.jpeg
which of course is not valid S3 or CDN path

In the guide that you refer to there is this section that seems relevant:

DISCOURSE_CDN_URL is a CDN that points to you Discourse hostname and caches requests. It will be used mainly for pullable assets: CSS and other theme assets.

DISCOURSE_S3_CDN_URL is a CDN that points to your object storage bucket and caches requests. It will be mainly used for pushable assets: JS, images and user uploads.

We recommend those being different and for admins to set both.

However, I’m not sure what to set as DISCOURSE_CDN_URL ? Should I set it to the same value as the DISCOURSE_S3_CDN_URL: https://dsxxxxx2qn.cloudfront.net or have a separate CDN instance created?

Then again maybe it’s something totally different :confused:

Thank you so much for all the help!

You have to configure CDN and it using your wanted domain on AWS’s side. Plus in DNS.

But why? Practically no one ever sees that URL.

1 Like

Hi Jake, I’m not sure I understand correctly what you mean. Could you please elaborate it a bit more?

Did you maybe mean that instead of setting the S3 bucket as the origin of the CDN I should set my forum.hobiguru.com domain as the origin? If that’s so I don’t think that would change anything since it is the discourse forum that generates those URLs that lead to nowhere e.g. //my-bucket-eu.my-bucket-eu/original/1X/7f242572bdb45b65ded727c13366fe490541358f.jpeg

I went on and added DISCOURSE_CDN_URL: https://dsuxxxhrz2qn.cloudfront.net also and now I’m waiting for the app to rebuild :crossed_fingers:

UPDATE: no, this did not work either :confused:

I really appreciate the help.
Thank you

You just can’t name a sub-domain only in app.yml. No one can’t use it without proper DNS info. And because serving your files happens from AWS you have to configure that side too, if you want to use CDN.

But again. Users see url of Disourse, if they want to see it. Quite rarely others than an admin doing something wants. And users practically never see url of medias or another static files.

So my point of view is you are wasting time for nothing if you don’t want to use CDN. And that may be smart if you have global audience, and some of them are behind bad state level connections.

I’m living in Finland. I don’t get any real benefits if a site on the other side of the world, in Australia, uses CDN (from a server that is located 1000 km away from me). The real bottle neck comes from how that site is builded, like if is used a lot of unnecessary PHP calls without enough resources.

But basically you can’t use an url cdn.example.tld without putting cdn at least in DNS.

Hi @Jagster

Actually, I don’t want to use a CDN at all—I just want all user uploads to be stored in S3 and served directly from there although CloudFront is trully a better solution than S3 directly.

My issue arose when I tried to set up S3 (specifically for serving assets, not uploads), and @pfaffman suggested I follow the Configure an S3 compatible object storage provider for uploads guide and configure a CDN.

Regarding your comment:

“You just can’t name a sub-domain only in app.yml. No one can’t use it without proper DNS info. And because serving your files happens from AWS you have to configure that side too, if you want to use CDN.”

I’m sorry, but I didn’t quite understand what you meant by this paragraph. Could you elaborate a bit more or clarify? Are you saying I need to configure DNS records for my S3 bucket or that there’s something specific I need to adjust on the AWS side?

Thanks in advance for your help!

Hi again, everyone,

I wanted to follow up on my previous post and share that I’ve made some progress.

What’s working now

  • User uploads are correctly served from my S3 bucket through the CDN (CloudFront), so that’s great!

However, I’m still facing an issue with the precompiled assets

The precompiled assets are still not being served correctly from the CDN

When I set the DISCOURSE_CDN_URL to the CloudFront URL (i.e., https://dsuqioxhrz2qn.cloudfront.net), the precompiled assets URLs become:

•	https://dsuqioxhrz2qn.cloudfront.net/stylesheets/color_definitions_shades-of-blue_7_1_e6f11758f9c015d1e5ed9b08c437e9c5c267c932.css?__ws=forum.hobiguru.com
•	https://dsuqioxhrz2qn.cloudfront.net/stylesheets/discourse-presence_308d905aa5c03567866fec50e9a28d8721ab0463.css

The problem is that these paths don’t exist in my S3 bucket. The precompiled assets are uploaded under /assets/* folder in S3 (e.g., /assets/locales, /assets/plugins, /assets/scripts), but there’s no /stylesheets/ folder and of course loading of those URLs are resulting in 403 forbidden.

If, however I change the DISCOURSE_CDN_URL: https://forum.hobiguru.com then my forum is working correctly, but the assets are now served from the server (e.g. https://forum.hobiguru.com/) and not from the CDN (e.g. https://forum.hobiguru.com/stylesheets/admin_308d905aa5c03567866fec50e9a28d8721ab0463.css?__ws=forum.hobiguru.com)

My current setup (for context) is:

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

and the precompile hooks:

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

It seems that after precomiling the assets there get uploaded to S3 into a certain structure, but then when loaded throught the CDN the path to the objects are a bit off