Archived May, 2026.

Configure an S3 compatible object storage provider for uploads

Discourse

:information_source: This topic covers how to configure some common S3 compatible Object Storage providers (S3 clones). See Set up file and image uploads to S3 for more details about Amazon AWS S3 configuration, which is officially supported and used internally by Discourse for our hosting services.

Provider Service Name Works with Discourse?
Amazon AWS S3 Yes
Digital Ocean Spaces Yes
Linode Object Storage Yes
Google Cloud Storage Yes
Scaleway Object Storage Yes
Vultr Object Storage Yes
BackBlaze Cloud Storage Yes*
Self-hosted MinIO Yes
Azure Blob Storage Flexify.IO Yes
Oracle Cloud Object Storage No [1]
Wasabi Object Storage Maybe
Cloudflare R2 No
Contabo Object Storage No

If you got a different service working, please add it to this wiki.

Configuration

In order to store Discourse static assets in your Object Storage add this configuration on your app.yml under the hooks section:

  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

When using object storage, you also need a CDN to serve what gets stored in the bucket. I used StackPath CDN in my testing, and other than needing to set Dynamic Caching By Header: Accept-Encoding in their configuration it works ok.

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.

Not using a CDN (or entering the bucket URL as the CDN URL) is likely to cause problems and is not supported.

In the following examples https://falcoland-files-cdn.falco.dev is a CDN configured to serve the files under the bucket. The bucket name was set to falcoland-files in my examples.

Configuring these settings in environment variables in your app.yml is recommended because it’s how CDCK does it in their infrastructure, so it’s well-tested. Also, the task to upload assets happen after assets are compiled, which happens in a rebuild. If you want to spin a Discourse that works properly with Object Storage since the beginning you need to set the env vars so the assets are uploaded before the site starts.

Choose your provider from the list below and add these settings to the env section of your app.yml file, adjusting the values accordingly:

AWS S3

What we officially support and use internally. Their CDN offering Cloudfront also works to front the bucket files. See Set up file and image uploads to S3 for how to configure the permissions properly.

  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 offering is good and works out of the box. It is fine to enable Restrict File Listing. Only problem is that their CDN offering is awfully broken, so you need to use a different CDN for the files. Also, you need not to install the CORS rule, as it re-installs it at every rebuild.

Example configuration:

  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

An extra configuration parameter, HTTP_CONTINUE_TIMEOUT, is required for Linode.

Example configuration:

  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

Listing files is broken, so you need an extra ENV to skip that so assets can work. Also skip CORS and configure it manually.

:warning: Since you can’t list files you won’t be able to list backups, and automatic backups will fail, we don’t recommend using it for backups. However, some suggest that if you change the role from Storage Legacy Object Owner to Storage Legacy Bucket Owner backups do work correctly. See this topic for Google Cloud specific discussion.

There is a third-party plugin to make the integration better at Discourse GCS Helper.

Example configuration:

  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 offering is also very good, and everything works fine for the most part.

:warning: Scaleway multipart uploads only support a maximum of 1,000 parts. This does not match Amazon S3, which supports a maximum of 10,000 parts. For larger instances, this will cause Discourse backups to fail and the incomplete upload may need to be manually deleted before further attempts are made. For small instances this is no issue however. Scaleway seem quite open to feedback, so if you want this limit changed you should contact them.

Note that for the DISCOURSE_S3_ENDPOINT parameter, Discourse uses the endpoint of the whole region: https://s3.{region}.scw.cloud. The “Bucket endpoint” found in your Scaleway dashboard comes in the form https://{bucketName}.s3.{region}.scw.cloud. Omit the bucket name subdomain to prevent connection errors.

Example configuration:

  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

An extra configuration parameter, HTTP_CONTINUE_TIMEOUT, is required for Vultr.

Example configuration:

  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

You need to skip CORS and configure it manually.

There are reports of clean up orphan uploads not working correctly with BackBlaze. You must change lifecycle rules for your bucket for orphan cleanup to work.

Example configuration:

  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

Note: During initial migration to B2, you may hit the 2500 free daily class C transactions limit. You will need to add a payment method to remove caps.

MinIO Storage Server

There are a few caveats and requirements you need to ensure are met before you can use MinIO storage server as an alternative to S3:

  1. You have a fully configured MinIO server instance
  2. You have Domain Support enabled in the MinIO configuration, for Domain driven bucket URLs. This is a mandatory setup requirement for MinIO and Discourse, as MinIO still supports the legacy S3 “path” styles which are no longer supported in Discourse.
  3. You have DNS configuration properly set up for MinIO so that bucket subdomains properly resolve to the MinIO server and the MinIO server is configured with a base domain (in this case, minio.example.com)
  4. The bucket discourse-data exists on the MinIO server and has a “public” policy set on it
  5. Your S3 CDN URL points to a properly configured CDN pointing to the bucket and cache requests, as stated earlier in this document.
  6. Your CDNs are configured to actually use a “Host” header of the core S3 URL - for example, discourse-data.minio.example.com when it fetches data - otherwise it can cause CORB problems.

Assuming the caveats and prerequisites above are met, an example configuration would be something like this:

  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 is still going to be enabled on MinIO even if the rule is not installed by the app rebuilder - by default, it seems, CORS is enabled on all HTTP verbs in MinIO, and MinIO does not support BucketCORS (S3 API) as a result.

Azure Blob Storage with Flexify.IO

Azure Blob Storage is not an S3-compatible service, so it cannot be used with Discourse. There is a plugin, but it is broken.

The easiest way to expose an S3-compatible interface for Azure Blob Storage is to add a Flexify.IO server which translates the Azure Storage protocol into S3.

As of this writing, the service is free on Azure, and you only need a very basic (cheap) VM tier to start running it. It does, however, require a bit of setup.

  1. In Azure portal, create a new resource of Flexify.IO - Amazon S3 API for Azure Blob Storage.
  2. For light usage, the minimum VM config seems to work just fine. You can accept most of the default config. Remember to save the PEM key file when you create the VM.
  3. Browse to the Flexify.IO VM link, and enter the system. Follow the instructions by setting up the Azure Blob Storage data provider and the generated S3 end-point. Make sure that the endpoint config setting Public read access to all objects in virtual buckets is true. Copy the S3 end-point URL and keys.
  4. Press New Virtual Bucket and create a virtual bucket. It can be the same name as your Azure Blob Storage container, or it can be a different name. Link any container(s) to merge into this virtual bucket. This virtual bucket is used to expose a publicly-readable bucket via S3.
  5. By default, Flexify.IO installs a self-signed SSL certificate, while an S3 endpoint requires HTTPS. SSH into the VM using the key file (the username is by default azureuser), and replace the following files with the correct files:
  • /etc/flexify/ssl/cert.pem - replace with certificate file (PEM encoding)

  • /etc/flexify/ssl/key.pem - replace with private key file (PKCS#8 PEM encoding, that’s the one starting with BEGIN PRIVATE KEY and not BEGIN RSA PRIVATE KEY which is PKCS#1)

    These files are root so you’d have to sudo to replace them. It is best to make sure that the replacement files have the same ownership and permissions as the original ones, which means root:root and 600 permission.

  1. By default, Flexify.IO creates a root-level S3 service with multiple buckets. Discourse requires sub-domain support for buckets. Go to: <your Flexify.IO VM IP>/flexify-io/manage/admin/engines/configs/1 which will open up a hidden config page!
  2. Specify the S3 base domain (say it is s3.mydomain.com) in the Endpoint hostname field, which should be blank by default. Press Save to save the setting.
  3. Restart the Flexify.IO VM in Azure portal.
  4. In your DNS, map s3.mydomain.com and *.s3.mydomain.com to the Flexify.IO VM IP.
  5. In Discourse, set the following in the admin page (yes, there is no need for the settings to be in 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>  (any container will do, as it does not require public read access and Flexify.IO will expose them automatically)
backup location: s3

Using the same bucket for production and staging is not recommended. If you do it anyway, take measures to see that your staging site doesn’t delete your production assets (set s3 disable cleanup as a minimum, and look out for it deleting production’s backups).

Wasabi

@pfaffman tried wasabi for backups, but it seemed to fail intermittently and silently, leaving backups on the hard drive and eventually filling the disk. Neither wasabi nor meta had any clues, so I don’t recommend it, though your mileage may vary. @pfaffman is now fairly certain that this problem was due to backups and automatic reboots somehow being scheduled at the same time; it was used only for backups, but seemed to work fine. If someone wants to give it a try and report here, it should work, at least for backups.

Oracle Cloud

Oracle Cloud lacks support for virtual-host style access to buckets and will not work

Cloudflare

Cloudflare’s offering is incompatible. In testing, @fearlessfrog filed a ticket with Cloudflare and in December 2022 they said:

Contabo

@tuxed tried to get Contabo Object Storage to work for S3 Compatible uploads. It seems that when uploading it prefixes the repository name in the url and he wasn’t able to get it to work.

Secure Uploads

Secure uploads are supported only for AWS S3. If your rake uploads:migrate_to_s3 fails you should enter these commands to first count and then mark as un-secure those uploads, given that you know that they do not need to be secure, in which case, you’ll need to use AWS S3.

./launcher enter app
rails c
Upload.where(secure: true).count
Upload.where(secure: true).update_all(secure:false)

  1. Oracle Cloud lacks support for virtual-host style access to buckets and will not work ↩︎

Richie

Hi everyone,

I’ve been using S3 storage for a number of years now without a CDN.

Following the advice given to me in another thread I have today setup CloudFront CDN.

Before I add the CDN URL to my control panel and rebake 230,000+ posts only to find out I’ve got a CloudFront setting wrong and break everything, can someone confirm this is the expected behaviour for me please? :bowing_man:t2:

Currently, this is an example URL that for an image that a user has uploaded:

https://greyarrows.s3.dualstack.eu-west-2.amazonaws.com/original/3X/8/3/8335cab232f512f4a979c7f0c8562e149c01b212.png

Which displays:

My CloudFront “Domain Name” is: d1q8cepst0v8xp.cloudfront.net

If I manually edit my example URL above and replace the existing S3 part of the domain name with the domain name of my CloudFront domain name, I get:

https://d1q8cepst0v8xp.cloudfront.net/original/3X/8/3/8335cab232f512f4a979c7f0c8562e149c01b212.png

And sure enough, the image still loads correctly:

Therefore, am I correct in thinking I simply need to add a S3 CDN URL of d1q8cepst0v8xp.cloudfront.net` to my Discourse control panel, rebake all posts and just sit back and wait of the magic to happen?

Thanks in advance, CDN is all new to me and I don’t have a development environment in which to safely test this :grimacing:

Richie

I also have the s3 configure tombstone policy setting enabled:

Will this be an issue? As I’m now using a CDN instead? Or are things in the background still checking the original S3 bucket, rather than a CDN URL?

I’m naturally thinking the latter, but again I can’t afford to kill of hundreds of thousands of my users photo uploads :scream:

:blush:

Richie

The answer is yes.

To test this theory, before rebaking hundreds of thousands of posts, I did the following sanity checks:

  • Uploaded an image
  • Changed the S3 CDN URL setting
  • Rebuilt the HTML on my test post (via the UI)
  • Refreshed the page in the browser
  • Checked the Network tab of the browser console to confirm the image was being pulled via cloudfront
  • Uploaded a new test image to a new post
  • Checked the Network tab of the browser console to confirm the image was being pulled via cloudfront

I’m now rebaking all posts as we speak :+1:t2:

scottfsmith

Thanks for the report Richie. I also have had AWS S3 image storage running for several years and came to this post via the console message. But the description at the top doesn’t say anything about the case that you already had S3 and just need a CDN.

For the record here is what I did:

  1. Went to AWS console, under Network and Content Delivery picked Cloudfront
  2. Clicked the Create distribution button
  3. Filled out the fairly obvious form, the only thing you really need to do on it is to pick your AWS S3 bucket where the images are from the drop-down menu.
  4. Waited a bit for the Cloudfront configuration to finish…
  5. A <gibberish>.cloudfront.net domain showed up in the “Domain Name” column of the Cloudfront Distributions list.
  6. I copied and pasted that domain into the s3 cdn url field in my site admin File settings.
  7. I did some tests:
    a. I made a new post with an image upload and indeed it was on cloudfront.
    b. I hit Rebuild HTML on some random existing image posts and saw they also rebuilt with cloudfront.net images.
  8. Since all looked good I went in and ran a rebake, which took several hours as I have around half a million posts now:
./launcher enter app
# rake posts:rebake
  1. All seems to be working fine. It put a ton of jobs in the sidekiq queue, one per post it looks like, which are going to take a few days to clear but it is chunking though them now.
Falco

Are you sure that is the case? This site here uses assets from CDN and we didn’t have to purge the cache. It’s also a EmberCli change that shouldn’t affect production :thinking:

Falco

Oh those damn optimizers. I would tell you to disable that if possible as Discourse already ships optimal configurations for each asset. Those optimizers are great when you are hosting a black box web software from the 2000’s, but they fail hard on modern stuff. Also even the big name optimizer from Cloudflare often breaks Discourse, so I have no hopes for others. They may work one day, and break the next and all your visitors are left with a blank page. All that for zero benefits.

Falco

Any chance you enabled secure_uploads in the site settings?

Also looks like this was reported and fixed today because of Discourse compatibility :

https://github.com/minio/minio/issues/12320

https://github.com/minio/minio/pull/12321

smlbiobot

Is there a way to disable this warning from showing up on my admin dashboard?

The server is configured to upload files to S3, but there is no S3 CDN configured.

I had issues setting up an S3 CDN, but it doesn’t cost me an arm and a leg so I am fine with just using S3 directly. But what I’d love to see is for this notification to go away because I am fully aware of the consequences.

tuanpembual

Hi.

I just want give update. We will able setup backup using GCS now. I post on other thread too. I hope it will help other people who painful search this solution.

How to do that?
Enable default config for backup(or you can setting form admin dashboard).

DISCOURSE_S3_BACKUP_BUCKET: falcoland-files/backup
DISCOURSE_BACKUP_LOCATION: s3

Then set bucket permission as Storage Legacy Object Owner:

  1. Go to your project in Google Cloud Console
  2. Select Storage
  3. Select your bucket
  4. Go to the permissions tab
  5. Add new permission, fill your service account email with your account. for roles, select Storage Legacy Object Owner
  6. Save and done.

Sorry for double post, I just want share this good update.
Thank you

tenzan

It’d be great if you could add Wasabi as well…

pfaffman

I used wasabi for backups for a while. As far as configuration goes, it “just worked”, so you could give it a try if you want.

But with some frequency the backups failed silently and backups stayed on the local machine, filling up the disk. I looked at wasabi and Discourse errors and never found an explanation that would make it possible for either end to “fix” anything.

I don’t recommend it, as I’m not sure that it’s “great.”

tenzan

Thanks!
I will check how it goes this time.
The default backup frequency is 7 days between backups and up to 5 backups.
I’ll share how it goes.

pfaffman

I was doing daily backups; I don’t remember how many I was trying to keep, but the local hard drive had room for only a couple.

tenzan

Which storage would you personally recommend?
I don’t think AWS and Azure are affordable for personal projects.
Not sure about Azure, but AWS looks confusing and unpredictable…

pfaffman

I hoped that wasabi would be good for backups at least. Backblaze s3 is affordable. I don’t think I’ve used it for uploads, but it works for backups (I think). I think the only issue with backblaze is that (when I last tested it) you had to use a global key (so I couldn’t use it for clients who could see the key). I think someone recently posted a fix for that (something about “legacy” something, somewhere). For a personal project, that’s what I’d try next, I think. (And if you’re on Digital Ocean, spaces is OK, I think.)

tenzan

I’m on DO, but cost-wise Blackblaze/Wasabi is cheaper.
What did you use for uploads?

tenzan

Sorry, I can’t get.
Why do we have to specify settings in app.yml, as we can enter this information within from Discourse->Settings ?

pfaffman

Because of the way that it handles building assets when the container is built, I think. It is quite confusing that the behavior is different when the settings are in the environment variables and the database, but that’s the way it works. It’s also a better way too handle them, as it means you can build and restore a new site from the command line.

Zup

Where should I set this? I’m not finding it in Discourse admin settings?

Falco

It’s set in the example configuration block for Vultr in the OP. Copy and paste into your app.yml and adjust the necessary fields.

Zup

Thanks, I missed this bit:

Zup

This isn’t going smoothly for me, sorry to reply so many times.

If I do the above, should I ignore the admin panel settings for s3 and backups?

Or should admin panel settings be configured as well?

Falco

You just need to follow this guide here in the OP and you will get a functional object storage configuration.

pfaffman

Setting those variables makes them unavailable from the UX. You must set them as described here rather than the ux.

Zup

I think it’s (mostly?) working now, but is this content security policy script src safe?

I’m using AWS for two S3 containers (for uploads & backups), and two CloudFront CDNs (for files & assets). When I use my own CNAMEs for the CloudFront CDNs, I get a bunch of script-src network errors in my browser when loading Discourse. No more errors after adding those entires to my CSP.

pfaffman

Are those the urls you put in the env variables described in the OP? And are they https?

Zup

Yes, I don’t have script-src warnings when I put the two d23whatever.cloudfront.net URLs in the env variables. When I put my custom URLs, i.e. community-cdn.mydomain and files-cdn.mydomain, in the env variables, that’s the time I get these script-src warnings. And apparently the stripe js is still giving me this warning even though it’s in my content security policy script src.

omarfilip

I set up S3 Uploads and object storage as outlined here in the OP, but without a CDN.

For the DISCOURSE_S3_CDN_URL variable, I have this:
https://my-bucket-uploads.s3.dualstack.us-west-2.amazonaws.com

All seems fine, including backups, however, in the console this error shows up when a reply to a post is started:

The request url in the error is actually a string of two urls which seems like the cause?

https://mydiscourse.com/t/uploads-test-for-s3/79/https://my-bucket-uploads.s3.dualstack.us-west-2.amazonaws.com/assets/markdown-it-bundle-a7328b73d3e7b030770eab70f10bdb0af655b3d8fa929bc49f1ad04c4cdaa198.br.js

Falco

A CDN is mandatory for it to work correctly.

unteem

I’m also in this situation with an object store configured (minio) but no CDN. Is it a use case that could be supported ?

From what I’m seeing so far in my tests there is only the markdown-it-bundle js file that is having issues as its pointing to the wrong URL - DISCOURSE_HOSTNAME/DISCOURSE_S3_CDN_URL/assets/markdown-it-bundle-HASH.br.js

It actually looks lit a bug for this one, if I set DISCOURSE_CDN_URL variable, it still points to the wrong URL in this form DISCOURSE_HOSTNAME/DISCOURSE_CDN_URL/assets/markdown-it-bundle-HASH.br.js

it should point to DISCOURSE_S3_CDN_URL/assets/markdown-it-bundle-HASH.br.js

Other js assets are pointing to the right URL ’

I guess from what you are saying I will have other issues that I have not identified yet. Maybe you can give me more info on what could go wrong ?

If I undestand it well, js assets are on the object store, stylesheets should be on a CDN. WIthout a CDN could the stylesheets be delivered by the app as usual ? (from what i’m seeing its the case)

Thanks for your help

Falco

That is not a supported use case per the OP:

quangmai911

Dear all,

I set up a new discourse server with Lightsail, using this guide for S3 uploads and backups setting-up-file-and-image-uploads-to-s3

After setup, I got the error shown “The bucket does not allow ACLs” on the screen when I upload an image

Here is my policy for S3:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:GetObjectVersionTagging",
                "s3:CreateBucket",
                "s3:GetObjectAcl",
                "s3:GetBucketObjectLockConfiguration",
                "s3:PutLifecycleConfiguration",
                "s3:GetObjectVersionAcl",
                "s3:PutObjectTagging",
                "s3:DeleteObject",
                "s3:DeleteObjectTagging",
                "s3:GetBucketPolicyStatus",
                "s3:GetObjectRetention",
                "s3:GetBucketWebsite",
                "s3:ListJobs",
                "s3:DeleteObjectVersionTagging",
                "s3:GetObjectLegalHold",
                "s3:GetBucketNotification",
                "s3:PutBucketCORS",
                "s3:GetReplicationConfiguration",
                "s3:ListMultipartUploadParts",
                "s3:PutObject",
                "s3:GetObject",
                "s3:DescribeJob",
                "s3:PutObjectVersionAcl",
                "s3:GetAnalyticsConfiguration",
                "s3:GetObjectVersionForReplication",
                "s3:GetLifecycleConfiguration",
                "s3:GetAccessPoint",
                "s3:GetInventoryConfiguration",
                "s3:GetBucketTagging",
                "s3:GetBucketLogging",
                "s3:ListBucketVersions",
                "s3:ReplicateTags",
                "s3:ListBucket",
                "s3:GetAccelerateConfiguration",
                "s3:GetBucketPolicy",
                "s3:GetEncryptionConfiguration",
                "s3:GetObjectVersionTorrent",
                "s3:AbortMultipartUpload",
                "s3:PutBucketTagging",
                "s3:GetBucketRequestPayment",
                "s3:GetAccessPointPolicyStatus",
                "s3:GetObjectTagging",
                "s3:GetMetricsConfiguration",
                "s3:PutObjectAcl",
                "s3:GetBucketPublicAccessBlock",
                "s3:ListBucketMultipartUploads",
                "s3:ListAccessPoints",
                "s3:PutObjectVersionTagging",
                "s3:GetBucketVersioning",
                "s3:GetBucketAcl",
                "s3:GetObjectTorrent",
                "s3:GetAccountPublicAccessBlock",
                "s3:ListAllMyBuckets",
                "s3:GetBucketCORS",
                "s3:GetBucketLocation",
                "s3:GetAccessPointPolicy",
                "s3:GetObjectVersion"
            ],
            "Resource": [
                "arn:aws:s3:::mybucket-upload",
                "arn:aws:s3:::mybucket-upload/*",
                "arn:aws:s3:::mybucket-backup",
                "arn:aws:s3:::mybucket-backup/*"
            ]
        }
    ]
}

And here is my setup public access for S3 bucket:

Would someone help me to solve this issue, please?
Thanks so much
Cheers,
Quang

Zup

Should my staging site use the same S3 bucket as my production site?

lucasbasquerotto

No, that would be very unsafe, and it could delete files that should still exist in the other environment and change files from the other environment (which could cause missing files, wrong files, and so on).

Both the buckets as well as the credentials should be different (and the staging credentials shouldn’t have access to the production bucket, specially regarding write and delete operations).

Maybe there’s a way using paths with different credentials for each path, but the chances of shooting your own foot are high, so I advise to use separate buckets.

Zup

DISCOURSE_CDN_URL and DISCOURSE_S3_CDN_URL need to be separate as well?

lucasbasquerotto

I assume so, because if your staging and production domains/urls are different (they are, aren’t they?), then DISCOURSE_CDN_URL (that ends up pointing to the CDN provider, which points to your website domain) is expected to be different for staging and production. The same logic applies to DISCOURSE_S3_CDN_URL (because different buckets should have different urls).

cookieman768

Hey all, I’m pretty new to S3, so I’m not entirely sure how to phrase this, but I’ll try my best. So, I just switched to using S3 for uploads and backups and I have been using Discourse Connect in order to allow for logins on other parts of my site, but now profile images don’t work. I believe this has to do with CORS policies, but I’m not sure where I could configure it. I would ideally want to whitelist it for forum.domain.tld and domain.tld - or a wildcard on all subdomains would work too. Is this something I would set in Discourse, or where exactly? I’m using Vultr object storage if that makes a difference.

Zup

Can versioning be enabled on the files S3 bucket? Is AWS Backup the recommended way to backup S3 buckets for Discourse?

Falco

Yes.

Using versioning, or syncing to a different region are all good strategies.

V1ktor

I wanted to add one thing for Backblaze, as I just set this up and this might save others some time:

Master application key is not compatible with S3 API. You must create new application key (source).

And I wanted to ask 3 questions, to clarify some things:

  1. Is it normal to have a lot of missing .map files? They all seem to be from brotli_asset folder. They are neither on the server nor object storage.
  2. I’ve seen reports that DISCOURSE_S3_BUCKET was deprecated and DISCOURSE_S3_UPLOADS_BUCKET should be used. Which is the correct one?
  3. Is it necessary to add DISCOURSE_ENABLE_S3_UPLOADS: true? I’ve seen this mentioned in other topics.

Thanks.

Falco

Yes, that is a know bug in our asset pipeline that will be solved by the ongoing ember-cli migration.

Warning is correct, gotta update the wiki guide here in the OP.

Not mandatory at the moment, because I’m pretty sure it gets overwritten by the USE_S3 ENV, but I would have to dig into the codebase for a definite answer on that.

pfaffman

I’m working on a multisite instance where I tried to restore a database from another instance and when I restored database-only the main page rendered json that said that it was required. But that’s lkely an edge case. I was always confused by the DISCOURSE_S3_BUCKET env variable…

cookieman768

I’m still curious about this if anyone has any insight, also I just had another question come up.

If I were wanting to change the domain of my Discourse installation, how would that impact Object Storage access policies? Would I need to change rules, or would that be taken care of for me by Discourse?

TheDarkWizard

@Falco

Have you seen this? https://blog.cloudflare.com/introducing-r2-object-storage/

I’ve already signed up for a test, looking forward to testing it.

pfaffman

I don’t know anyone who’s seen it.

I signed up for that test long ago, back in October. It doesn’t seem to be an actual product.

TheDarkWizard

Interesting.

I got an email about it roughly 2 weeks ago in regards about signing up for the test, it’s the only reason why I learned about it. I don’t follow the cloudflare blog. Hopefully it doesn’t get shoved into the back like the railgun though Argo is just so much better.

pfaffman

Maybe I missed a memo! Or maybe I got it and just don’t remember. (The most recent email I see with r2 in it says “Thank you for your interest in the Cloudflare R2 Storage early access program. We will be in touch regarding your request.” last November…)

TheDarkWizard

Fair enough. I just went back to the blog, and also noticed the date for last September. Considering how recent the email asking me to sign up (I did do so), I thought it was a more recent product announcement/offering. I don’t really keep up with cloudflare news, to be honest. Heres to hoping it marteralizes and that it’s actually good, their scope and pitch about the fees could be really enticing.

Falco

I signed up as soon as it was announced and I’m on the same boat

TheDarkWizard

I was so excited that I thought I brought something to Meta that people had barely heard about yet xD

pfaffman

There does exist documentation: https://developers.cloudflare.com/r2/get-started/

It looks very unpleasant to configure.

TheDarkWizard

I guess they misunderstood what they meant when they said that it was supposed to be an easy drop in replacement for amazon s3 and other s3 compatible services.

itsbhanusharma

Given what they did with tunnels, I guess they’ll introduce a GUI once the product gets enough traction. Let’s wait & see how it grows.

pfaffman

Could I submit a PR for a new template called something like web.upload-assets.template.yml that includes that stanza so that then people could just include it? It’s a bit fussy to paste it in to the yml.

And if that’s OK, could I also submit a PR including it commented out standalone.yml and web_only.yml so that it can easily be included?

luizjr

I’m having difficulties configuring Oracle’s object storage.
I didn’t see any guides here.

Falco

There is no Oracle Cloud guide as it’s not that popular option. If you are experimenting with it, try starting with the DigitalOcean settings and going from there.

When you get it to work you can update the wiki in the OP with the guide.

luizjr

I did the configuration and it didn’t work, besides that I didn’t understand the logic of the CDN

Falco

Walking off the beaten path of already tested services is not for the faint of the heart.

I strongly recommend using AWS S3, which is what we use internally.

pfaffman

Then you likely didn’t do the configuration correctly. If you included the details of your setup (minus the keys) we could offer help, and test that the CDNs were correct. Also, an easy thing to overlook is the bit at the top about pushing assets to S3. Which is also hard to understand.

dsaver

Would love to say your post is the best.

luizjr

I found the problem, is that Oracle Object Storage, uses path style.

And Discourse doesn’t give me the option to use path style, it wants to force me to use virtual host style.

I wish I could choose that.

Even the minio has to be configured to suit the virtual host style.

Falco

Considering that every major cloud provider supports virtual host style (even MinIO) we have no plans on adding support for the deprecated path style feature.

pfaffman

This isn’t the first time I remember your stating that. Maybe add that to the OP and explicitly say that Oracle Object Storage isn’t supported until they support virtual host style.

luizjr

The above explanation is reasonable, but it should be made clearer that any provider that is not using the Virtual Host Style standard is not supported.

Despite having this in some points it is not very clear.

I had to do some testing to find out.

RGJ

Which service did you try that did not work? Then we can add it to the list in the start post.

luizjr

I tried with Oracle Object Storage

They are still using “path style” and that’s why it didn’t work.

Victor_Ashiedu

I just configured S3 backup using DigitalOcean Space. When I finished adding the information my * app.yml file and successfully running ./launcher rebuild app when I tried the rebake command, rake posts:rebake, I receive an error message that rake cannot be found.

Please help! I am stuck!

pfaffman

Before you enter the rake command you’d

 ./launcher enter app

You might do a rebuild html on a post from the UX first to make sure it’s working.

Victor_Ashiedu

Thanks @pfaffman. I did run the command:

./launcher enter app

before I ran the rebake command.

You also said “You might do a rebuild html on a post from the UX first to make sure it’s working.”

I don’t know how to do this as I am new to Discourse. Would you mind providing me the steps to do this?

Victor_Ashiedu

Since the guide here does not specify, after entering these details to app.yml, and running the necessary command, do I still need to configure the settings in Settings → File and Settings → Backup?

Benjamin_D

Hi Victor,
on your site, clicking on the three dots (the ellipsis) you’ll find the wrench and there rebuild html

pfaffman

No. Putting the settings in env variables overrides the ability to see it change then in the ux

Victor_Ashiedu

Thanks, @Benjamin_D. I will do this shortly.

Victor_Ashiedu

Thanks for your help.

I have successfully completed the S3 backup config (or so I think!). But when I run backup, it runs successfully.

However, my DigitalOcean Space bucket has no files in them!

Victor_Ashiedu

Here is my configuration. I did not include my access and secret keys for obvious reasons!

  after_assets_precompile:
    - exec:
        cd: $home
        cmd:
          - sudo -E -u discourse bundle exec rake s3:upload_assets
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: NYC3
DISCOURSE_S3_ENDPOINT: nyc3.digitaloceanspaces.com
DISCOURSE_S3_ACCESS_KEY_ID: myaccesskey
DISCOURSE_S3_SECRET_ACCESS_KEY: mysecretkey
DISCOURSE_S3_CDN_URL: https://community-cdn.itechguides.com
DISCOURSE_S3_BUCKET: itg-community-files
DISCOURSE_S3_BACKUP_BUCKET: itg-community-files/backups
DISCOURSE_BACKUP_LOCATION: s3
pfaffman

All of those DISCOURSE*: x lines go further up in the file in the section that starts with env:, like right under the SMTP stuff.

Victor_Ashiedu

Wao! Let me move the files now and test.

Should I also move the script below?

after_assets_precompile:
- exec:
cd: $home
cmd:
- sudo -E -u discourse bundle exec rake s3:upload_assets

pfaffman

That section is its own stanza so it doesn’t matter where it goes (except in the middle of another one).

Victor_Ashiedu

Thanks so much @pfaffman! I have just added those files in the relevant places and after rebuilding the container, my site is down displaying a blank page!

pfaffman

You can have a look at the javascript console. My guess is they either the CDN is wrong or they you didn’t get the precompile assets part right.

https://community.itechguides.com/ is working now:

image

If it’s not working for you try a hard reload and/or an incognito window.

Victor_Ashiedu

The site opened for you because as of when you opened it, I had commented out the following lines from the app.yml file:

DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: nyc3
DISCOURSE_S3_ENDPOINT: https://nyc3.digitaloceanspaces.com
DISCOURSE_S3_ACCESS_KEY_ID: accesskey
DISCOURSE_S3_SECRET_ACCESS_KEY: secretkey
DISCOURSE_S3_CDN_URL: https://community-cdn.itechguides.com
DISCOURSE_S3_BUCKET: itg-community-files
DISCOURSE_S3_BACKUP_BUCKET: itg-community-files/backups
DISCOURSE_BACKUP_LOCATION: s3

I just re-enabled the lines and rebuilt the container. Now, the site is showing a blank page again!

The screenshot below shows where I placed the codes in my app.yml. As you can see, I placed the S3 configuration codes below DISCOURSE_NOTIFICATION_EMAIL


a

Jagster

What happends if you comment out DISCOURSE_CDN_URL?

Victor_Ashiedu

I haven’t done that. But I have been troubleshooting and I strongly believe that I did not set up the S3 CDN correctly. I am using StackPath and I am not sure what to use in the Origin address and the Host header

Victor_Ashiedu

Another thing I am not sure of is how to set up the file listing feature of my DigitalOcean’s Space bucket. Now, I am using Restrict Listing. Does this affect anything?

Victor_Ashiedu

I commented out DISCOURSE_S3_CDN_URL and the site loads. This confirms that my setup of the S3 CDN is the problem but I still don’t know how to set it up correctly.

I will really appreciate any help.

md-misko

Did you complete all tasks in the Configuration section?

If I remember correctly, setting DISCOURSE_S3_CDN_URL in app.yml requires that assets are stored on S3.

Jagster

I don’t know much how Discourse works. I’m just another copy&pasting webmaster from PHP-world, but I’m still wondering why there would be need to declare same CDN twice.

I don’t use DISCOURSE_CDN_URL because I have DISCOURSE_S3_CDN_URL (and propably any doc I red didn’t guide to use it). So I tried.

I added DISCOURSE_CDN_URL: <cdn-url>. Rebuilding gave no errors, but I got error 502. When I removed it my forum worked again.

Still your issues can happend because of some misconfiguration somewhere else. But I like easy solutions, even when I’m wrong, and I’m blaiming situation when you are telling twice CDN for different needs. Or something.

Victor_Ashiedu

DISCOURSE_CDN_URL and DISCOURSE_S3_CDN_URL are different. While DISCOURSE_CDN_URL points to your forum, DISCOURSE_S3_CDN_URL points to your S3 storage URL.

The idea is for DISCOURSE_CDN_URL to serve pullable assets like CSS while DISCOURSE_S3_CDN_URL serves pushable assets like JS, images and user uploads.

I have been able to get everything working but my S3 storage CDN. Whenever I enable that bit in the app.yml file, my forum displays blank.

A look at the browser inspect element network shows that assets delivered by DISCOURSE_S3_CDN_URL are showing error 404.

This is where I am stock! I am not sure why the S3 CDN cannot deliver the assets.

Jagster

Thanks for patient explanation!

That is quite… unfamiliar for me. But as I said, I have very limited experiense. I’m using AWS as CDN thru S3/CloudFlare in WordPress but only for static files — scripts would need another setup. I reckon there is no point to compare WP and Discourse because those are fundamentally so different platforms. But I’m trying to understand principles of he concept here.

Well, I got much more now than you :smile:

EDIT: Aaaand I was totally wrong at my setup too :flushed: All JS, images, etc are served thru CDN. But I couldn’t find CSS’ there.

Victor_Ashiedu

Yes, they are. But thanks for the update.

Victor_Ashiedu

Hi @Jagster I really will appreciate your help.

The problem I am having now is that my site is trying to load .gz.js assets from the Object Storage CDN but the files are not there. How do I force Discours to upload those .gz.js assets to the Object Storage?

Falco

That’s what this bit in the guide does:

Victor_Ashiedu

I already have that line in my app.yml. I put the above code after defining the plugins. Or do I move them above the plugin lists?

Falco

That’s wrong. The after_assets_precompile YAML key must be under the hooks key.

By default we ship as:

## Plugins go here
## see https://meta.discourse.org/t/19157 for details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

and you want

## Plugins go here
## see https://meta.discourse.org/t/19157 for details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
  after_assets_precompile:
    - exec:
        cd: $home
        cmd:
          - sudo -E -u discourse bundle exec rake s3:upload_assets
Victor_Ashiedu

Thank you so much, @Falco. I’ll move them now and try again.

Victor_Ashiedu

But what about the other plugins? Is it okay to list them below

  • sudo -E -u discourse bundle exec rake s3:upload_assets ?
Falco

No.

It will become:

## Plugins go here
## see https://meta.discourse.org/t/19157 for details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/docker_manager.git
  after_assets_precompile:
    - exec:
        cd: $home
        cmd:
          - sudo -E -u discourse bundle exec rake s3:upload_assets

YAML is tree-like data structure and white space indentation defines the structure.

Victor_Ashiedu

With the guidance you (@Falco) and @pfaffman provided, I have just successfully completed this configuration.

For other community members that wish to see my configurations. Here are the screenshots. I also wrote a comprehensive guide while I was configuring all these.

I used StackPath and DigitalOcean Spaces. My guide includes a step by step of the whole configuration. If anybody needs this guide, I will be happy to post the URL when requested.

Victor_Ashiedu

@Falco and @pfaffman thank you both so much for your help. This is my first time configuring Discourse but I have just completed the most difficult bits (I think!). I am very grateful!.

pfaffman

So it’s working now?

Victor_Ashiedu

Perfectly. It took me so long but apart from the fact that it is working, I have also learned so much about Discourse configuration!

Thank you!

Victor_Ashiedu

OK. I decided to post the step-by-step guide I created when I was performing this configuration.

How To Configure Discourse Forum S3 Backup And S3 CDN (Itechguides.com)

The steps in this guide is for using DigitalOcean Space and StackPack CDN.

Victor_Ashiedu

@pfaffman I was wondering whether you could help me with this additional backup problem:

After completing the S3 backup and cloning configuration, my automatic backup is not running. The screenshot below shows my configuration.

I can run backups manually. The problem is the scheduled automatic backup - they do not run

pfaffman

Don’t know. You can look at the sidekiq jobs and make sure they are running. It should work.

pfaffman

4 posts were split to a new topic: Tips on Google Cloud S3

tuanpembual

Hi,

Thanks for correct my post. But I cannot edit my post to avoid misleading information.

Jerome_Hordies

Hi,

I’m a bit stuck and confused and hope somebody can help me.
I first had a bitnami install and realized how much trouble this would give me along the way, I reinstalled using the standard install.
I was able to restore my backup and everything was fine, even though I went from the 2.8 to the 2.9 beta.

I tested again my backup on my google bucket and it still worked like a charm.

Note that all the S3 config was done through the web interface and not via ENV variables.

For GDPR reasons, I created a new backup bucket in europe (lets call it discourse-backup-eu ), and now that I was able to change the ENV variable, I set DISCOURSE_S3_ENDPOINT: https://storage.googleapis.com, rebuild the app, changed the backup bucket name in the web interface, reran the backup and I was very please to see the backup files appearing on my new backup bucket in europe.

Now I wanted the uploads to go to another bucket and avoid filling up my vm disk space.

So I configured a new bucket (lets call it discourse-uploads), made it public, added the Storage Legacy Bucket Owner role to my service account on that new bucket.
Then added a rule to my existing load balancer (lets call it https://www.example.com) to use a backend bucket with cloud CDN enabled as instructed here. The rule being /discourse-uploads/* points to the bucket discourse-uploads

I tested my CDN with a test.jpg in the root of the bucket but I couldn’t reach it via https://www.example.com/discourse-uploads/test.jpg and had to create a subfolder called discourse-uploads inside the bucket, moved the test.jpg inside and now I can see my test picture via https://www.example.com/discourse-uploads/test.jpg

In the web UI, I changed the dummy bucket name under “s3 upload bucket” (I was forced to set previously while setting up the backup) to discourse-uploads, filled the CDN URL with https://www.example.com/discourse-uploads and ticked “enable s3 uploads”.

From there on, if I would try to upload a image, I would get a popup saying Invalid Argument in the browser window (coming from a 422 error with a json content saying basically the same).

I tried to rebake all post, but had no effect, I still had the error.

So I figured, I should try using the env variables instead of the Web UI.

and use the following config:

DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: whatever
DISCOURSE_S3_INSTALL_CORS_RULE: false
FORCE_S3_UPLOADS: 1
DISCOURSE_S3_ENDPOINT: https://storage.googleapis.com
DISCOURSE_S3_ACCESS_KEY_ID: MY_KEY_ID
DISCOURSE_S3_SECRET_ACCESS_KEY: MY_ACCESS_KEY
DISCOURSE_S3_CDN_URL: https://www.example.com/discourse-uploads
DISCOURSE_S3_BUCKET: discourse-uploads/discourse-uploads
DISCOURSE_S3_BACKUP_BUCKET: discourse-backup-eu
DISCOURSE_BACKUP_LOCATION: s3

I rebuilt the app.
Then I cannot open discourse anymore because none of the assets were uploaded to the bucket and get a 404
https://www.example.com/discourse-uploads/assets/admin-31467dc73634cbfb81799737c43df0e2939307d893ef32713f1d0770bcb3532c.br.js

I thought that trying to upload directly to a sub folder in the bucket directly was a bit of a stretch enven though the OP suggests it works (at least for the backup bucket)

changed the env variable to
DISCOURSE_S3_BUCKET: discourse-uploads
(Thinking that later I can play with the host rule instead to avoid having to upload to a sub folder)

and rebuilt to see if anything gets uploaded, but nothing gets uploaded to the bucket and discourse still fails to open because of 404s.

So my questions are :

  • Do the Web UI and ENV variable collide ?
  • When are the assets supposed to be uploaded to the bucket ?
  • How can I debug this ? I don’t see any error in the logs
  • Is it possible to set a subfolder of a bucket in the config ?
  • Once this works, Are the previously uploaded images transferred to the bucket ? If I rebake, what will the url of the previously uploaded images look like ?

Thank you !

pfaffman

Did you include this bit?

I submitted a PR with a template to do that a while back but I don’t think it ever got any attention.

Also, changing buckets is hard. You need not only to copy all of the assets from the old one to the new one, but also update the database to use the new bucket. There is a topic about it, I believe.

If you use the ENV variables (which you should) those settings are no longer visible in the Web UI.

pfaffman

A post was merged into an existing topic: Tips on Google Cloud S3

pfaffman

Yes. If my memory serves me, there is discussion above about google not allowing something (list access, maybe?), but there was a workaround about using some “legacy” something. That’s what I remember. You’ll have to scroll through the above 100 messages to find it. If it works, it would be great if you could update the OP to say how you made it work so the next person who needs to know will be able to find it more easily.

Jerome_Hordies

Thanks again for your answer !
The warning about google bucket was about using for backups because it couldn’t list the files.
I already posted on how to fix this

Are you suggesting I update the OP with that information ? I don’t believe I can.

Again, the backup works, but the upload of the assets doesn’t, according to the OP, this was supposed to work even without the Storage Legacy Bucket Owner rights.

I think there might be a regression here, what do you think @Falco ?

Falco

There may be a regression. Are you sure you added the custom

that only Google needs?

pfaffman

Oh. Well, I thought that somebody had. :person_shrugging:

That was what I was suggesting. It’s a wiki, so I’m pretty sure you can, though I’m not 100% sure what trust levels are involved.

Jerome_Hordies

Thanks for your answer, yes I did includes it:

Note that I tried with and without the subfolder
DISCOURSE_S3_BUCKET: discourse-uploads/discourse-uploads
and
DISCOURSE_S3_BUCKET: discourse-uploads

Thanks again

Jerome_Hordies

@tuanpembual initially did but referred to Storage Legacy Object Owner instead of Storage Legacy Bucket Owner

I’m only a “basic user” that must be the reason I can’t edit it.

Jerome_Hordies

I will try to summarize the answers to my questions:

  • Do the Web UI and ENV variable collide ?
  • When are the assets supposed to be uploaded to the bucket ?
    By adding this snippet to the app.yml in the hook section, it will be uploaded after_assets_precompile (during rebuild app).
  • How can I debug this ? I don’t see any error in the logs
    By running :
cd /var/discourse
sudo ./launcher enter app
sudo -E -u discourse bundle exec rake s3:upload_assets --trace
  • Is it possible to set a subfolder of a bucket in the config ?

You can use prefixes to organize the data that you store in Amazon S3 buckets. A prefix is a string of characters at the beginning of the object key name. A prefix can be any length, subject to the maximum length of the object key name (1,024 bytes). You can think of prefixes as a way to organize your data in a similar way to directories. However, prefixes are not directories.

  • Once this works, Are the previously uploaded images transferred to the bucket ? If I rebake, what will the url of the previously uploaded images look like ?
Fabrice

Hi, I’ve been looking for object storage providers, and I saw on the OP that for some of them, you’ll need “to skip CORS and configure it manually.”, I am not familiar with CORS or anything about configuring it, so should I stay clear from the ones needing this setting, or is it simple to set it up ?

pfaffman

If you need to ask (as I would) then I would go with another one.

knewt

Just confirm, once I’ve done the

rake uploads:migrate_to_s3
rake posts:rebake

steps, I can remove the local uploads folder in it’s entirety, yes?

pfaffman

Hey @mcwumbly. This was very easy to find when I could search for “S3 clone”. I was unable to find it just now. Was there something wrong with that title? Is there a search that will find it? Could we add a (I can’t remember what it’s called) thing so it can auto link on some words like standard install does (but I can’t think of what words to use).

Falco

As someone who links that topics multiple times a week I kinda agree :stuck_out_tongue:

Maybe adding “s3 clones” to the OP body helps the search-fu?

mcwumbly

I’ve found “S3 compatible” more common in the wild, which is why I changed it during a sweep of updating docs titles in general, for example: MinIO | AWS S3 Compatible Object Storage

I think the suggestion to stick other search terms in the OP body makes sense though. (I just added it in this one).

pfaffman

Seems fine. I guess we’ll have to change with the times. :person_shrugging:

Yes. It’s really not so hard. You can do it, @pfaffman!

@falco:

image

tuxed

Hello, has anyone managed to get Contabo Object Storage to work for S3 Compatible uploads. It seems that when uploading it prefixes the repository name in the url.

For example if you have a bucket called community it creates a URL like https://community.eu2.contabostorage.com

I have found this behavior in Duplicati for example but it can be excluded that it prefixes the bucket name in the domain.

I would appreciate if someone has the solution to be able to use this Object Storage because it has very good prices.

I have made several tests to configure the domain as CNAME in my domain from cloudflare to provide the SSL but for community.cdn.midominio.com the SSL certificate is no longer covered because they use a wildcard and if I deactivate the proxy of clouflare it complains because the certificate is not correct.

Greetings,

Falco

Have you tried to set the S3 CDN setting to https://community.eu2.contabostorage.com ? IMO that will work.

tuxed

Not exist, its the contabo endpoint eu2.contabostorage.com

Falco

Yes, but what will be the final URL of a example file in a bucket?

tuxed

![](upload://u6BBQfNFGrA4yuaLeqABnVkt87U.png)
pfaffman

He means that if you upload a file to the bucket yourself (using whatever tool you can get to upload a file) what url would you use to access the file?

tuxed

https://eu2.contabostorage.com/9198f3bf2d6e43dd86fab037ebad3aee:comunidad/castopod-1.png

The structure is

Host: https://eu2.contabostorage.com/
User: 9198f3bf2d6e43dd86fab037ebad3aee
Bucket: comunidad
File: castopod-1.png

pfaffman

That’s not a working url. But I guess it might be if you replace that colon with a slash?

That’s not the way you described it in your first post, so maybe now he can make another suggestion.

Falco

So try setting

  DISCOURSE_S3_CDN_URL: "https://eu2.contabostorage.com/9198f3bf2d6e43dd86fab037ebad3aee:comunidad"

and rebuilding.

pfaffman

Cloudflare’s R2 is finally publicly available (it took just a year, apparently). (Here’s the original announcement: Announcing Cloudflare R2 Storage: Rapid and Reliable Object Storage, minus the egress fees)

I created a bucket.

I created a token that includes: “Edit: Allow edit access of all objects and List, Write, and Delete operations of all buckets”

Here’s what I’ve tried:

  DISCOURSE_USE_S3: true
  DISCOURSE_S3_REGION: auto
  DISCOURSE_S3_ACCESS_KEY_ID: redacted
  DISCOURSE_S3_SECRET_ACCESS_KEY: redacted
  DISCOURSE_S3_CDN_URL: https://pub-72eaa03782c542edbe00598fd1666be1.r2.dev
  DISCOURSE_S3_BUCKET: lc-testing
  DISCOURSE_S3_BACKUP_BUCKET: lc-testing/backups
  DISCOURSE_BACKUP_LOCATION: s3
  DISCOURSE_S3_ENDPOINT: https://cb46accbfcc3db1bdbba2bce07f8b509.r2.cloudflarestorage.com
  DISCOURSE_S3_INSTALL_CORS_RULE: false
  DISCOURSE_S3_CONFIGURE_TOMBSTONE_POLICY: false
  FORCE_S3_UPLOADS: 1

But uploading assets fails with this:

Aws::S3::Errors::NotImplemented: Header 'x-amz-acl' with value 'public-read' not implemented

And then I remembered to make the bucket public as described at Public buckets · Cloudflare R2 docs

But it still didn’t work.

S3 API compatibility · Cloudflare R2 docs shows that x-amz-acl is unimplemented.

Glancing at the Discourse code, it isn’t obvious to me that it’s possible to make R2 work without changes to core.

After disabling uploads, backups work, so R2 appears to be a very cheap way to have S3 backups. But since I had made that bucket public, the backup was also public (if you can guess the filename), so if this does get figured out, you’ll want separate buckets for backups and uploads.

I removed this line and was able to see that it uploaded a file, and was able to access it using a custom domain as the s3_cdn_url. (And a similar edit to the s3 rake task allows assets to get uploaded.)

Falco

So I guess we add it as not compatible in the OP until they implement object level ACL. Thanks for trying it out!

pfaffman

Yeah. The required changes to core to allow it to skip setting the ACL seem pretty hairy. You could say that it’s OK for backups only. If you don’t jump through hoops to make the bucket public, it should be fine.

tuxed

The problem is the s3 endpoint

Falco

I just tested R2, but it appears they are not respecting our “Content-Encoding” info, even tho their docs say they will. Maybe in a year it will be usable.

teward

This needs a warning blurb added to the MinIO or general sections. We need a notice made in here that “Discourse uses DNS mode for paths on S3-compatible storage systems. If the backend only supports path-mode and not DNS mode for bucket paths, then it is not Discourse compatible.” Which is why MinIO was originally not on the list and later added.

I also need the MinIO Storage Server section updated - i need the caveat #2 to state the following:

  1. You have Domain Support enabled in the MinIO configuration for Domain-driven bucket paths. This is mandatory as Discourse does not support non-domain path-driven bucket paths with S3 storage mechanisms.

EDIT: Looks like with this post I got Member status (trust level 2) so I was able to edit the wiki post now. No action needed from moderators, even though I asked them to make the edits.

pfaffman

Awesome! Thanks for your help in keeping things up to date. That looks like the kind of warning I’d be happy to have.

:clinking_glasses: :palms_up_together:

teward

Thanks for the thank you! I did flag for mod attention becuase I didn’t have edit rights at that point, but I’ve got them now thanks to the post I made. Ironic how that works huh?

But before I make a global blurb outside the MinIO section, can we confirm that Discourse as a whole does not support non-domain based paths anymore like this post started my edit hunt for?

If we know that Discourse as a whole does not support path mode (i.e. minio.server.com/BUCKET/foo/bar/... paths) and instead only supports domain paths (i.e. BUCKET.minio.server.com/foo/bar/...) then we can make that a global notice in the wiki and I’ll be happy to do so - however I need to hear it from someone far higher up the chain than me (as a simple community person) that this IS in fact the requirement for Discourse. If it is, then I can edit it in, otherwise… well, then I’ll just leave it as a blurb in the MinIO requisites.

Falco

MinIO is the only popular S3 clone with a past of using the now deprecated S3 path style, so I do not think it warrants a global warning, just in the MinIO section is enough.

teward

Thanks, Falco, I’ve left it in the MinIO requisites, but put some strong emphasis on that caveat section as well because of the linked thread above that refers to why i’m poking again.

Nick_Tomlinson

Seem to have an issue:

Entered

  after_assets_precompile:
    - exec:
        cd: $home
        cmd:
          - sudo -E -u discourse bundle exec rake s3:upload_assets

Rebuilt:

FAILED
--------------------
Pups::ExecError: cd /var/www/discourse && sudo -E -u discourse bundle exec rake s3:upload_assets failed with return #<Process::Status: pid 2064 exit 1>
Location of failure: /usr/local/lib/ruby/gems/2.7.0/gems/pups-1.1.1/lib/pups/exec_command.rb:117:in `spawn'
exec failed with the params {"cd"=>"$home", "cmd"=>["sudo -E -u discourse bundle exec rake s3:upload_assets"]}
bootstrap failed with exit code 1
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one.
./discourse-doctor may help diagnose the problem.
Falco

Can you follow the guidance and

Falco

Added a step to clean up old assets on S3 to the OP. Should work everywhere but GCP.

pfaffman

Most of the 170K files uploaded on rake s3:migrate_to_s3, but I think 12 had this:

: Unsupported value for canned acl 'private' (Aws::S3::Errors::InvalidArgument)

Maybe those were in PMs? Is there something I can do to fix those?

pfaffman

Hey @Falco. Does this make sense? I’m going through the replies to see that they’ve been dealt with so that we can turn on the delete-after-30-days thing on this topic.

I checked a few of the uploads marked private and they were in regular topics, so I couldn’t figure out why they were marked secure. (Secure uploads wasn’t set?)

See above

Falco

Secure Uploads are AWS S3 only, so it won’t work with any of those clones indeed.

pfaffman

Makes sense. I updated the top of the OP with that info. Any idea why local uploads would have been marked as secure on a site that didn’t have S3 or secure uploads enabled?

Falco

Someone enabled that for sometime and then rolled it back when saw that it didn’t work?

pfaffman

I think that this problem with uploading to Cloudflare R2 may be resolved with Upload.where(secure: true).update_all(secure: false). I’ll try to get to that before this message gets deleted (but I added a note to the OP).

fearlessfrog

Hmm, we don’t have any secure uploads. I think I’m going to give Cloudflare R2 a go, as there free limits are pretty generous and they have a (beta) S3 migrator. I guess I’ll find out, but did you see if R2 was ok in the end @pfaffman?

pfaffman

I can no longer remember if the issue was when I tried to upload images or when I just uploaded a new one. Thinking about it again, I would think that I tested it on a brand new site.

Migrating to a different S3 platform is rather tricky. There are some topics about that, but if you want to use Cloudflare R2 I would first try it out on a test site; there is a very good chance it won’t work.

fearlessfrog

It sort of works, but not ready for production usage.

I had an older Discourse 2.7 local dev install hanging around and it worked fine, as in image uploads, use of CDN and backups to a private bucket when set up for Cloudflare R2. I updated to latest 2.9 (like our forum uses) and it seems fail on the Jobs::UpdateGravatar catch-up processing, where it is use the bucket notation incorrectly for Cloudflare where it tries to cache a gravatar remote image to R2. Example (where my bucket name on R2 is ‘uploads’):

Upload Update (0.3ms) UPDATE "uploads" SET "url" = '//uploads.123123redact.r2.cloudflarestorage.com/original/1X/123123example.jpeg', "updated_at" = '2022-12-12 20:44:02.929494', "etag" = '9c02b086b2aa5e2088ed44e1017fa63e' WHERE "uploads"."id" = 3

So I’d start up the UI and the avatars in my local test/dev set-up will be pointing to

//uploads.123123redact.r2.cloudflarestorage.com/original/1X/123123example.jpeg

So my best guess is that S3 is fine with the bucket dot notation and cloudflare R2 isn’t, or maybe the gravatar cache needs to be using the S3 CDN value instead?. It’s a shame as it seems pretty close…

fearlessfrog

I got a reply from Cloudflare that for R2, until the implement the object acl correctly, they’ve changed it to return a 200 if they get values in that property they don’t support yet. This changed behavior on R2 about end of November apparently. Obviously not ideal (it’s in a public bucket, with the API asking it to be private) but means for this issue it now ‘works’.

pfaffman

Oh! That does sound promising. I think maybe you’d need a separate bucket for uploads, though it would be quite a guessing game to get a backup’s filename.

I’ll try to have a look at this Real Soon Now.

fearlessfrog

I do use separate upload and backup buckets, and it did seem to work ok, in that it backup R2 bucket is not set to public and Discourse via the admin UI wrote a compressed backup in there ok. I downloaded it and had a look and it seemed sane (not the same as an actual restore, but good enough for a Monday). My uploads bucket I’ve tested out with a custom domain setting for the S3_CDN and that seems to work well.

To be honest I can’t really tell what’s up with my 2.9 not rendering a UI in the ember-cli (it blanks on me after creating the admin user), but it’s probably something you’ll see wrong quickly.

EDIT: Oh, it seems like it’s trying to load the plugin javascript assets from Pseudo-S3/R2 e.g. lots of 404’s on things like assets/locales/en.br.js

I don’t get any luck with a bundle exec rake s3:upload_assets, so that’s my best current clue.

EDIT2: Yes, it’s assets related, in that if I clear my DISCOURSE_S3_CDN_URL then the UI loads. I’ll try just manually uploading the assets in place for now.

EDIT3: The issue just seems to be one of the app needing the assets to be precompiled and where DISCOURSE_S3_CDN_URL is pointing, and for a dev environment locally that’s not usual. Will be interested in what @pfaffman finds, as I think this would work in a proper docker deployed self host instance, using the after_assets_precompile hook for R2.

pfaffman

Yeah. A CDN for a local dev environment? I can’t imagine that it could work. It does sound like it should work for a production deployment.

fearlessfrog

Yep on retrospect not surprisingly in a dev set-up. I think what I wasn’t expecting was that with DISCOURSE_S3_CDN_URL set to the Cloudflare CDN for R2 but then DISCOURSE_CDN_URL set to blank (or a local or ngrok) but then it still wanted to use the Cloudflare pull URL for the precompiled assets etc and not just the uploads/images alone. I think it will work in production ok in a proper container, so I might do a quick try. My plan will be something like make media uploads TL4 temporarily, switch the IDs etc to Cloudflare in the app.yaml, test it out and, if good, leave it to R2 and then rclone all the existing S3 objects across - after that I’ll rebake the posts and hopefully everything will be fine :crossed_fingers:.

fearlessfrog

Had to park this for now, as it looked like was going to work but then there is something odd going on with R2 in terms of content encoding with the assets either on uploading and not setting the header or something else. It’ll choke on a ‘Invalid or unexpected token’ given the gz asset of something like browser-detect-7af298cd000a967d2bdc01b04807eda2924a388584ea38ad84919b726283c2ed.gz.js. The rake s3:upload_assets seems to be working but the files aren’t being read correctly on the browser side.

I don’t really get why with AWS S3 it is fine using the local server URL for assets (they don’t exist on our existing S3 bucket for uploads) but for R2 use it wants to use DISCOURSE_S3_CDN_URL for assets only. If I could force the assets to be from the server URL this would probably all work.

EDIT: Chatting on the CF, this seems to be the issue, and as of today why R2 can’t be used with Discourse without some changes. I could script something in the post hook step to remove the gz assets but I feel I’m already ‘off the path’ far enough for one day:

Files that you gzip are not currently handled correctly by R2. You have to upload uncompressed files. Cloudflare has transparent compression, they pick identity, gzip, or Brotli based on what the client can handle. This is a difference from S3.

pfaffman

Nice work! And that’s a clear message from cloudflare about why it won’t work. Thanks very much. I’ll copy that into the OP soon.

pfaffman

Thanks again! I updated the OP:

saulshanabrook

Thank you for putting together this guide! I have had some success using Minio.

For anyone else who is trying to set it up locally with Docker Compose, you can tell Docker to add a hostname alias so that it works as a subdomain, like this:

  minio:
    image: minio/minio
    command: server --console-address :9001 /data
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - ./data/minio:/data
    environment:
      MINIO_DOMAIN: minio.mydomain.com
    networks:
      default:
        aliases:
          - assets.minio.mydomain.com

In this case, you would set DISCOURSE_S3_ENDPOINT=http://minio.mydomain.com:9000, DISCOURSE_S3_CDN_URL=//assets.minio.mydomain.com:9000, and set your local /etc/hosts/ file to point the subdomain to localhost.

This works mostly fine, but I did notice that Discourse is unable to download files from an address that doesn’t have port 80 or 443, so uploading an image will work, but then when it attempts to download it to resize it, it will fail.

I was thinking it might be good to mention that in the Minio section or in summary, that the DISCOURSE_S3_CDN_URL must be on port 80 or 443.

fearlessfrog

Hey @Falco - Is this referring to the way the Content-Encoding: gzip header works with their Spaces CDN? That sounds similar to Cloudflare R2, in that the asset locations is made to be the same as the uploads CDN, so the gzip breaks? Here’s what happens with R2 today.

It might be worth considering a toggle for that behavior, i.e. serve assets from origin rather than always DISCOURSE_S3_CDN_URL? I’ll happily go look to see how to do this, if it would be considered as a potential config change.

Falco

That’s what should happen if you omit configuring DISCOURSE_S3_CDN_URL but since it’s a weird corner case, and a potential expensive mistake, it’s not a common configuration.

fearlessfrog

Yep, I can understand that. A new GlobalSetting bool S3_ORIGIN_ASSETS (or S3_BROKEN_PROXY_FUDGE :slight_smile:) entry around about here, sort of like for how the test scripts aren’t compressed would allow Digital Ocean Spaces and Cloudflare R2 storage and CDN to work with Discourse out of the box though, which is a nice feature add for not much effort? Maybe for future consideration anyway. :heart_eyes_cat:

fearlessfrog

Oh, I saw on the 3.0.beta release notes there’s something added. I’ll give it a go, unless I misunderstand what it’s for? It might allow Cloudflare R2 and Digital Ocean Spaces to be used with their CDNs doing that weird stuff with gzip.

Falco

No, that’s unrelated.

fearlessfrog

The setting allowed me to specify the local site as the origin, to get around the need for the js assets to be on the S3 site (in this case Cloudflare or Digital Ocean Spaces with CDN enabled). Thanks to @david for the change, even if that wasn’t the intention.

pfaffman

Do you enter the site url for the asset cdn? Clever!

satonotdead

Hi folks, anybody knows if that could be related with Discourse?

That’s the XML of the files that we tried to upload to our previously ‘working with Discourse’ S3 storage:

<Error>
<Code>InvalidArgument</Code>
<Message>
Requests specifying Server Side Encryption with AWS KMS managed keys require AWS Signature Version 4.
</Message>
<ArgumentName>Authorization</ArgumentName>
<ArgumentValue>null</ArgumentValue>
<RequestId>ID</RequestId>
<HostId>
ID
</HostId>
</Error>
pfaffman

Are you using AWS? Something else?

Is that bucket configured with server side encryption?

It could be that a library got updated and is behaving differently.

satonotdead

Thanks, I double-checked and it seems to work with auto configuration but not managing my own keys from S3 management.

Do you know if can be possible within Discourse?

Falco

3 posts were split to a new topic: Why run UpdatePostUploadsSecureStatus even when secure uploads is disabled?

aosus

this seems to have been fixed recently.
In the 2023-3-16 changelog it lists bug fix for gzip files handling.

We are running our discourse forum at discourse.aosus.org with R2 right now(haven’t run migrate_to_s3 yet), and it seems to be OK!, no noticeable issues so far.

  DISCOURSE_USE_S3: true
  DISCOURSE_S3_REGION: "us-east-1" #alias to auto
  #DISCOURSE_S3_INSTALL_CORS_RULE: true #it should be supported
  DISCOURSE_S3_ENDPOINT: S3_API_URL
  DISCOURSE_S3_ACCESS_KEY_ID: xxx
  DISCOURSE_S3_SECRET_ACCESS_KEY: xxxx
  DISCOURSE_S3_CDN_URL: your cdn url
  DISCOURSE_S3_BUCKET: BUCKET_NAME

is there a way to specify a separate hosts for backups?, it would be great if its possible to leave R2 just for CDN stuff.

pfaffman

There is not. It seems unlikely to me that this will change.

Falco

23 posts were split to a new topic: Troubles configuring Object Storage

Hyan

It’s wired that the settings in ENV do not reflect in admin UI. Does overriding happen? Will new settings of S3 in admin UI override those in environment?

pfaffman

Yes. Env variables override values on the database and are hidden from the UX.

markersocial

@Falco - It could be good to add a warning for Scaleway, that it only supports 1,000 parts for multipart upload, while AWS supports 10,000. This is not a problem for regular uploads, but it is an issue for backup uploads over a certain size as the S3 SDK will use 10,000 parts unless manually modified and fail.

https://www.scaleway.com/en/docs/storage/object/api-cli/multipart-uploads/

Falco

Great finding! Please add it to the OP wiki if you can.

charlot_Johanson

Thank you, also I would to add that you can use any of these tools to copy from cloud to cloud, especially to/from S3 compatible object storage, for example, Rclone, Shargate, Gs Richcopy360 and GoodSync. all of these are compatible with similar clouds

aosus

We have just discovered a problem, Cloudflare R2 doesn’t allow public-read from the S3 endpoint URL, rather only the custom domain or a random r2.dev domain.
(Pre-signed downloads work, just no direct public access is supported.)
But discourse only uses the CDN URL for embedded images, and not direct downloads, which use the S3 endpoint URL.
Is there a way to make it use the CDN URL for all files, or force the use of a presigned url?

Related:

The workaround mentioned in that post works, add ?dl=1 fixes it, because its forces discourse to use a presigned S3 URL.

ARHAEEM

Fixed in 2023-03-16 now R2 working with Discourse like charm with free plan

markschmucker

I also see this with some frequency (every several months) even though my Discourse is running in AWS Lightsail and I’m uploading to AWS S3. So I’m not sure it’s wasabi’s fault.

Would it be possible to catch this error and alert the admin? I do check the disk space and remove old backups when I upgrade but sometimes that’s too late and the forum goes down for no disk space.

pfaffman

I am fairly certain that the issue was that automatic OS reboots for security updates were happening while the backup was running. Make sure that you schedule your OS reboots and your backups at different times. It was after I’d moved that site from wasabi that I came up with this explanation, but I’m pretty sure that’s what it was.

markschmucker

uptime says it’s been up for 300 days so I don’t think that’s the problem. But along similar lines, I had Discourse backups scheduled at 2:00 am and Lightsail snapshots at 2:30 am, so maybe the upload sometimes isn’t complete and the snapshot messes with it. I’ve separated the two operations by an hour- we’ll see if it makes a difference.

Regardless I think it’s reasonable to warn admins if the upload fails, for whatever reason.

pfaffman

I think that it’s time that you do kernel upgrades and reboot. :slight_smile:

Could you be running out of ram?

Brandon007

After implementing remote Backblaze backups, I see this error in my dashboard:

The server is configured to upload files to S3, but there is no S3 CDN configured. This can lead to expensive S3 costs and slower site performance. See “Using Object Storage for Uploads” to learn more.

I didn’t configure uploading of files, I only configured backups via this config:

DISCOURSE_S3_REGION: "s3.us-west-00X"
DISCOURSE_S3_INSTALL_CORS_RULE: false
DISCOURSE_S3_ENDPOINT: https://s3.us-west-00X.backblazeb2.com
DISCOURSE_S3_ACCESS_KEY_ID: mykeyid
DISCOURSE_S3_SECRET_ACCESS_KEY: myaccesskey
DISCOURSE_S3_BUCKET: community-forum
DISCOURSE_S3_BACKUP_BUCKET: community-forum/backups
DISCOURSE_BACKUP_LOCATION: s3

Did I do something wrong?

Something seems misconfigured, I notice when I try uploading a file to a post, I received this error:

Unsupported value for canned acl 'public-read’

Any assistance would be appreciated.

pfaffman

Remove this if you don’t want uploads to go to s3.

Brandon007

You saved the day brother. :+1:t3: Thanks so much!

pfaffman

Did that seem to work?

markschmucker

It has happened once in the past month since I separated the two processes by an hour, so it didn’t “fix” it, and it doesn’t happen often enough to say whether it helped.

On the bright side, I noticed there is a backup status section on the admin page that shows available disk space, which saves me from constantly opening a terminal and doing a df just to check for stuck backups. I customized the text to remind myself that I expect around 80 GB free.

image

pfaffman

That’s a good idea.

I saw the image before I read that you had customized the text and was wondering what logic was at play to determine that was “good”!

noplanman

I just couldn’t get this to work with Scaleway using the Bitnami Discourse image.
The env variables were set but clearly weren’t being read/applied correctly (or at all?).

So I’ve set the S3 variables in the admin panel and set the region directly in the rails console (still hoping that this just becomes a text field):
SiteSetting.s3_region="fr-par"

It gave me a validation error, but I just commented out the validation check before updating the setting, then put it in again.

Falco

The Bitnami image isn’t packaged by us and don’t follow our recommendations. Everything documented here is only tested against the official install.

aosus

This has been solved by enabling “s3 use cdn url for all uploads”, an option recently added by discourse.
since we were using R2 before, we needed to use discourse remap to manually replace the broken links, and synced s3 files just in case, and then we rebaked all posts.

thepaperpilot

I’m trying to set this up with idrive e2, which is s3 compatible. However I’m getting a not very helpful error/stack trace at the end of ./launcher rebuild app:

I, [2023-10-14T15:08:08.026184 #1]  INFO -- : > cd /var/www/discourse && sudo -E -u discourse bundle exec rake s3:upload_assets
rake aborted!
Aws::S3::Errors::InternalError: We encountered an internal error, please try again.
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-core-3.130.2/lib/seahorse/client/plugins/raise_response_errors.rb:17:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/sse_cpk.rb:24:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/dualstack.rb:27:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-s3-1.114.0/lib/aws-sdk-s3/plugins/accelerate.rb:56:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/checksum_algorithm.rb:111:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/jsonvalue_converter.rb:22:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/idempotency_token.rb:19:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/param_converter.rb:26:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-core-3.130.2/lib/seahorse/client/plugins/request_callback.rb:71:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-core-3.130.2/lib/aws-sdk-core/plugins/response_paging.rb:12:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-core-3.130.2/lib/seahorse/client/plugins/response_target.rb:24:in `call'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-core-3.130.2/lib/seahorse/client/request.rb:72:in `send_request'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-s3-1.114.0/lib/aws-sdk-s3/client.rb:12369:in `put_object'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/aws-sdk-s3-1.114.0/lib/aws-sdk-s3/object.rb:1472:in `put'
/var/www/discourse/lib/s3_helper.rb:78:in `upload'
/var/www/discourse/lib/tasks/s3.rake:41:in `block in upload'
/var/www/discourse/lib/tasks/s3.rake:41:in `open'
/var/www/discourse/lib/tasks/s3.rake:41: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.2.0/gems/rake-13.0.6/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
(See full trace by running task with --trace)
I, [2023-10-14T15:08:16.413098 #1]  INFO -- : Installing CORS rules...
skipping
Uploading: assets/admin-2ebebf57104b0beb47a1c82fe5a8c6decd07f60a706640345fed296a094d1536.js

This is the config I’ve been using, but I’ve also tried it with DISCOURSE_S3_CONFIGURE_TOMBSTONE_POLICY and DISCOURSE_S3_HTTP_CONTINUE_TIMEOUT

  DISCOURSE_USE_S3: true
  DISCOURSE_S3_REGION: Dallas
  DISCOURSE_S3_ENDPOINT: https://y0o9.tx21.idrivee2-4.com
  DISCOURSE_S3_ACCESS_KEY_ID: <snip>
  DISCOURSE_S3_SECRET_ACCESS_KEY: <snip>
  DISCOURSE_S3_BUCKET: discourse
  DISCOURSE_S3_INSTALL_CORS_RULE: false

Note I’m not using it for backups (that’s already setup in the UI with backblaze) nor DISCOURSE_CDN_URL because I’m not sure idrive supports that - I planned on experimenting with that once I got some actual files in the bucket.

Falco

Looks like it’s not compatible enough with S3 for Discourse needs.

If you want to dig further the next step would be reproducing this in a development install and getting the exact API call that fails.

Skeleton

Contabo S3 support/compatibility will be added? or someone found a walkaround to make it works?

Falco

We, the Discourse maintainers, only support AWS S3. The providers listed here were tested by either us or the community to see if they implement enough of the S3 API to be compatible with Discourse.

Per the OP, @tuxed tested Contabo and found it lacking. It’s on Contabo to evolve their implementation compliance with S3, if they deem it aligned with their business interests, not something that can do.

pythonskynet

Is this still buggy? Why Digitalocean CDN not good?

pfaffman

Did you follow the links?

It looks like the CDN doesn’t now about metadata. But you could try it an see if it works! Let us know if you do. I was wondering if it had been fixed just the other day. From the looks of the documentation, I’m not going to be trying it myself any time soon.

pythonskynet

I am looking for an easy way to add cdn support to my forum on digitalocean. If S3 is easier I would go with that option.

Don’t want to take risk with a setup that doesn’t worked well before.

pfaffman

The recommended solution is just not to use their CDN. You can use spaces, if you follow the instructions above and something like bunny.net for the CDN. It’s cheap and easy.

Aws S3 is what cdck uses, so it’s a bit better tested and supported, but unless you’re already handy with aws, the spaces bucket is a good solution. Just don’t use the digital ocean cdn.

kgrier

I just went through this - CDN setup, keeping images local for now - first with fastly, then some other I don’t recall. Settled on bunny.net. very easy to set up. They have how-to specific to Discourse. We are self-hosted in DO with 100GB+ of images. 65% cache hit rate and climbing.

Harrison_Jhonson

s3 configure tombstone policy only works on aws.amazon ?

pfaffman

No. It’s a problem only on backblaze.

Falco

3 posts were split to a new topic: Exploring Solutions for User Profile Picture Upload Problems

FizzGiGG

Whew, where do I start? So, I’m using Cloudflare for caching and DNS, and Backblaze B2 for storage. I was able to get it to work, but only partially. During a ./launcher rebuild app I saw that it was uploading assets, so I was super excited that it appeared to be working. After it completed the rebuild successfully, I was unable to access the site. I just get some moving dots in the middle of the page.

Based on the Backblaze article Deliver Public Backblaze B2 Content Through Cloudflare CDN I have set a Proxied CNAME record that points to the Friendly URL origin f000.backblazeb2.com called gtech-cdn.

CNAME gtech-cdn → f000.backblazeb2.com

The article also talks about Page Rules; I have tried toggling them on and off to no avail.

Here’s the pertinent configuration items:

  DISCOURSE_HOSTNAME: mmhmm.com

  DISCOURSE_CDN_URL: https://mmhmm.com

  DISCOURSE_USE_S3: true
  DISCOURSE_S3_REGION: us-west-000
  DISCOURSE_S3_ENDPOINT: https://s3.us-west-000.backblazeb2.com
  DISCOURSE_S3_ACCESS_KEY_ID: <secret>
  DISCOURSE_S3_SECRET_ACCESS_KEY: <secret>
  DISCOURSE_S3_CDN_URL: https://gtech-cdn.mmhmm.com
  DISCOURSE_S3_BUCKET: gtech-uploads
  DISCOURSE_S3_BACKUP_BUCKET: gtech-uploads/backups
  DISCOURSE_BACKUP_LOCATION: s3

Under the **hooks:** section...

  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

One of the things that is confusing to me is what to put in the two variables DISCOURSE_S3_CDN_URL, and DISCOURSE_CDN_URL. Do I have them set properly based on the info that I have provided?

Looking at the browser dev tools console, I’m getting 404 errors on .js scripts. The URL doesn’t appear that it is being built properly. Shouldn’t it have /file/ in there before /assets? If I add that manually to create a proper URL, it works:

https://gtech-cdn.mmhmm.com/file/gtech-uploads/assets/google-universal-analytics-v4-e154af4adb3c483a3aba7f9a7229b8881cdc5cf369290923d965a2ad30163ae8.br.js

Thanks for any help, it’s much appreciated!!!

pfaffman

https://gtech-cdn.mmhmm.com doesn’t resolve, so that’s the first thing to fix. .

I’m not sure that you can use cloudflare as acdn like that, but maybe I’m wrong.

FizzGiGG

Sorry, I should have mentioned that mmhmm.com is a fake domain. It does respond to a ping.

As far as Cloudflare not being able to be used as a CDN, I guess I’m not following. The article I linked clearly is for using it as a CDN. If that is not true, then again, what values are to be used in the two variables DISCOURSE_S3_CDN_URL, and DISCOURSE_CDN_URL?

Cheers,

pfaffman

If you give fake urls you can only get fake answers.

Does the url serve the data that is expected? Can you retrieve it from the forum url?

I think the s3 cdn should work. It’s using the forum url for the forum cdn they I’m not sure about.

A normal cdn is a different url than the forum and the cdn can count on the data being static rather than having to guess what’s dynamic

FizzGiGG

I do my best not to plaster my information across various forums, so please excuse my secrecy on the matter.

The forum sits at “https://mmhmm.com”, which is a Cloudflare DNS record that is proxied (cached). Prior to configuring Discourse to use Backblaze it all functioned properly.

https://gtech-cdn.mmhmm.com”, as stated previously, resolves and also responds to a ping. The target of the CNAME record, f000.backblazeb2.com, also resolves. That B2 Friendly URL origin is what the article instructs you to use. That isn’t the issue though. The issue is that Discourse is serving up URLs for the .js files using an invalid URL that will never work as it is missing that “/file/gtech-cdn” part of the path. If you take one of those incomplete .js URLS and add that missing info to it manually, it will load the text of the .js file just fine.

Of course, I’m still trying to wrap my head around how this is all supposed to be working with those two variables. I’m more of a visual learner and could really use a flow chart or something to help me understand what’s supposed to be happening with the interactions between Cloudflare CDN, Discourse, and Backblaze B2.

Thanks for your help.

FizzGiGG

Oh, and I’ll try to address your last sentence about a normal cdn…

The article from Backblaze has you create two page rules per bucket (in my case 1 bucket is used), which if I am understanding it correctly is sort of like a firewall rule in the way it processes.

Rule 1 says that https://gtech-cdn.mmhmm.com/file/*/* should use standard caching (which is set elsewhere in Cloudflare to 1 month)
Rule 2 redirects anything (302 - temp redir) that doesn’t match the Rule 1 pattern.

So not everything will be cached by going to mmhmm.com… at least that is my understanding

FizzGiGG

EDIT: This did not work.
Focusing on this a little bit more, I decided for obvious reasons that I should use the S3 URL as the CNAME target instead of the Friendly URL that the Backblaze article suggested. I’m now just waiting on the DNS record TTL to expire.

image

Jeff_Vienneau

Regarding this hook:

I don’t see anything with s3 in the rake --tasks dump. Is this still relevant or am I missing some plugin?

Also seeing this when I manually run:
uploads:migrate_to_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.2.0/gems/rails_multisite-6.0.0/lib/rails_multisite/connection_management/null_instance.rb:49:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/rails_multisite-6.0.0/lib/rails_multisite/connection_management/null_instance.rb:36:in `each_connection'
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/rails_multisite-6.0.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>'
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'
Tasks: TOP => uploads:migrate_to_s3
(See full trace by running task with --trace)
root@ubuntu-s-2vcpu-4gb-nyc2-01-app:/var/www/discourse# 
root@ubuntu-s-2vcpu-4gb-nyc2-01-app:/var/www/discourse# rake uploads:migrate_to_s3
Please note that migrating to S3 is currently not reversible! 
Falco

6 posts were split to a new topic: Cloudflare R2: Navigating Setup and Handling Configuration Errors

pfaffman

Looks like Cloudflare works now:

See Cloudflare R2: Navigating Setup and Handling Configuration Errors - #13 by pfaffman

Master

Has scaleway changed anything? It had worked for me until 48 hours ago but it no longer works.

pfaffman

Is your bill paid? What is wrong? Do any images work? They are all gone or you just can’t add new ones?

CAKE_NICE

Can you add a little more support? For example, Tencent COS from China is more convenient for Chinese users, and Tencent Cloud’s COS has CDN nodes around the world, which is very fast to access

pfaffman

Have you tried it? Does it work?

CAKE_NICE

I have used it in the test environment, but I can only back up to Tencent COS, and I hope that the discourse official can add Tencent COS support to facilitate developers from China

pfaffman

I think that you’ll need to share what you’ve done and what errors or problems you had. Then someone might be able to suggest how to make it work. You might look at the other examples and see if you can use those to make it work.

I think it’s unlikely that they’ll make changes in core to support it.

SimeonGriggs

Backblaze:

  • I’ve setup a B2 bucket in my account
  • Added details to the env section of app.yml
  • Run ./launcher rebuild app

…but I don’t see any confirmation in my Discourse instance dashboard that these settings have taken effect. Where should I look?

kamaljain

Hi,

I could successfully test and use Cloudflare R2 for both uploads and backups. Detailed post here Cloudflare R2: Navigating Setup and Handling Configuration Errors - #40 by kamaljain

Would request to kindly test at your end and review the “Works with Discourse” to Yes for Cloudflare R2. Infact its easier than S3 and more economical, free if <10gb of storage.

pfaffman

I too tested a setup on multisite and also think that it’s working.

I’ve seen something that makes me wonder if you can get a list of backups. I’ll try to check my setup.

kamaljain

I can see the backups listed. Havent tried the restore though.

MinhVN

Hi bro, can I chat with you, Im have some problem when config with minio.
Thankyou.

JamesNorth

iDrive Config

Just wanted to report that using iDrive’s E2 version of s3 storage works perfectly with these settings:

ENV settings in yaml file

Make sure your bucket is has at least Public & Read permissions in iDrive’s settings.

These are the settings I use for one bucket sharing uploads and backups.

DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: your-region
DISCOURSE_S3_ENDPOINT: https://your-idrive-endpoint.dev
DISCOURSE_S3_ACCESS_KEY_ID: your-access-key
DISCOURSE_S3_SECRET_ACCESS_KEY: your-secret-key
DISCOURSE_S3_CDN_URL: https://your-custom-cdn-url.com/uploads
DISCOURSE_S3_BUCKET: your-bucket-name/uploads
DISCOURSE_S3_BACKUP_BUCKET: your-bucket-name/backups
DISCOURSE_BACKUP_LOCATION: s3
DISCOURSE_S3_INSTALL_CORS_RULE: false

By default iDrive has Share everything in this region with every origin … so it should work out of the box regardless of sources. Lock it down to your own domains if you want to.

I use a Cloudflare origin certificate to create a CNAME that points to the iDrive endpoint.


Sync Existing Attachments

Rebuild

Rebuild the app after changing these ENV settings.


Upload and Rebake

Then enter the container and run

rake uploads:migrate_to_s3

Watch it upload, then run

rake posts:rebake_uncooked_posts

Exit the container


Add to hooks section of yaml file

In hooks section

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

This ensures that js/css stuff gets uploaded to iDrive after your attachments do, otherwise you’ll get a bunch of console errors in the browser as they’re all missing.


Rebuild

Rebuild again after assets command goes in.


Everything should be ok!

NateDhaliwal

Perhaps Hetzner’s Object Storage service should be added to the table?

tumbano

I managed to use Contabo for file uploads. Both old (migrated) files and new uploads worked just fine. In my case the bucket url was https://eu2.contabostorage.com/mybucket
The trick was to set EU2 as bucket name and https://contabostorage.com/mybucket as endpoint.
The only problem is that when loading the site it also requests other files like plugin’s js from the bucket and it doesn’t load being the files unavailable. Well, I understood this is because I’ve set CDN url same as bucket. This isn’t very clear to me yet, can someone tell me how to set it up? From what I understood I’ve to create a cname address that points to the main domain (discourse server) and proxy it with cloudflare, is this correct?

pfaffman

You missed this bit:

tumbano

I’m sure I did it, but maybe I made a mistake. In the end, I restored a backup, so I’m going a bit by memory… But then, I wonder, why is it discouraged to set a CDN as the Bucket? What problems can it cause? Will retry tomorrow.
Thanks

pfaffman

I don’t think the problem you describe would be because you set the CDN url as the bucket url (that is, if uploads work, but assets don’t).

tumbano

Will update you tomorrow, thanks

tumbano

And it worked :partying_face:
Step by step of what I did hoping to help others:

edited app.yml and added

  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

after hooks: (just after git clone plugins…)
and

  DISCOURSE_USE_S3: true
  DISCOURSE_S3_REGION: EU
  DISCOURSE_S3_ENDPOINT: https://contabostorage.com/bucketname
  DISCOURSE_S3_ACCESS_KEY_ID: accesskey
  DISCOURSE_S3_SECRET_ACCESS_KEY: secretaccesskey
  DISCOURSE_S3_CDN_URL: https://eu2.contabostorage.com/randomlettersthatcontaboaddstothelinks:bucketname
  DISCOURSE_S3_BUCKET: eu2
  DISCOURSE_BACKUP_LOCATION: s3
  DISCOURSE_S3_INSTALL_CORS_RULE: false

after the email settings
then I’ve set the same values in discourse menu and enabled S3 uploads.
Rebuilt the app with

cd /var/discourse
sudo ./launcher rebuild app

then

./launcher enter app
rake uploads:migrate_to_s3

This takes a bit, in my case a few hours (80k files, 100GB)

When finished

rake posts:rebake_uncooked_posts
tumbano

Update: some users were unable to load the site (assets and files). We’ve found that the contabostorage.com domain was present in some blocklists as a phishing site. The solution was simple:

setup a subdomain files.mydomain.com like described here Can I Setup a Custom Domain for My Object Storage? : Contabo

Updated DISCOURSE_S3_CDN_URL: https://files.mydomain.com in app.yml

Then

cd /var/discourse
sudo ./launcher rebuild app

and to complete the job

./launcher enter app
rake posts:rebake

Now all assets and uploads load from https://files.mydomain.com/pathtofile/file.ext

Done

pequiste

I do not seem to have wiki edit permission, but I did successfully use a different provider.

OVHcloud

Service name: Object Storage

Regions correspond to data centers which are identified by a three letters code. If you don’t know where you created your bucket, check in the object storage tab in your customer portal.

DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: [data center code]
DISCOURSE_S3_ENDPOINT: https://s3.[data center code].io.cloud.ovh.net/
DISCOURSE_S3_ACCESS_KEY_ID: [key]
DISCOURSE_S3_SECRET_ACCESS_KEY: [key]
DISCOURSE_S3_BUCKET: [bucket name]
DISCOURSE_S3_BACKUP_BUCKET: [bucket name]
DISCOURSE_BACKUP_LOCATION: s3
pfaffman

Did you make OVHcloud S3 work for uploads or just backups?

pequiste

Initially both in my test version but I went to prod with only backups since the prod machine has a ton of space anyway.

It’s very compatible S3, but there are some things missing like lifecycle rules to delete old files or move them to cold storage which are being actively worked on by OVH. It works fine to serve files though.

So for backups I just used Discourseʼs option to delete old backups on its own.

kneel

This is a really disappointing and completely unhelpful response. What exactly is the issue? Linking to a support document that changes means that no one can actually tell what the heck the “awful brokenness” mentioned in this thread here.

You mention “metadata” and that the CDN “doesn’t know about it”. What metadata? It would be helpful to know what isn’t working.

JamesNorth

I just wanted to add to this post of mine with instructions on how to use iDrive’s E2.

There appears to be a thing that iDrive has recently switched on that causes access keys that are assigned only to one bucket to fail unless a bucket auth check is bypassed.

You can bypass this when using rclone with no_check_bucket = true in the rclone.conf file, but I’m not sure such an ENV setting exists for Discourse building.

As a result, with iDrive E2, you currently must use a key that has access to write to all your buckets, rather than just one.

tknospdr

Why would someone else know the exact issue for a provider they don’t use?

Anyway, it looks like we’re almost there with Cloudflare R2. Per:

When I entered all the info in the Web UI new uploads went to S3 storage correctly, and backups are going to S3 correctly. Current uploads did not move obviously.
So I then went to the app.yml and entered this info:

## This set of lines allows R2 S3 hosted files to be uploaded and downloaded..
  DISCOURSE_CDN_URL: https://eufiles.technospider.com
  DISCOURSE_USE_S3: true
  DISCOURSE_S3_ENDPOINT: https://randomnumber.r2.cloudflarestorage.com
  DISCOURSE_S3_CDN_URL: https://eufiles.technospider.com
  DISCOURSE_S3_BACKUP_BUCKET: exotics-unlimited-backups
  DISCOURSE_INCLUDE_S3_UPLOADS_IN_BACKUPS: true
  DISCOURSE_BACKUP_LOCATION: s3
  DISCOURSE_S3_BUCKET: exotics-unlimited
  DISCOURSE_S3_REGION: auto
  DISCOURSE_S3_ACCESS_KEY_ID: randomnumbers
  DISCOURSE_S3_SECRET_ACCESS_KEY: randomnumbers
  DISCOURSE_S3_INSTALL_CORS_RULE: false

## The Docker container is stateless; all data is stored in /shared
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## Plugins go here
## see https://meta.discourse.org/t/19157 for details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
#         - git clone https://github.com/discourse/discourse-subscriptions.git
          - git clone https://github.com/discourse/discourse-follow.git
          - git clone https://github.com/discourse/discourse-solved.git
          - git clone https://github.com/communiteq/discourse-private-topics.git
#         - git clone https://github.com/discourse/discourse-assign.git
          - git clone https://github.com/tknospdr/discourse-auto-remove-group.git
          - git clone https://github.com/discourse/discourse-topic-voting.git
          - git clone https://github.com/discourse/discourse-livestream.git
#         - git clone https://github.com/discourse/discourse-calendar.git
          - git clone https://github.com/jannolii/discourse-topic-trade-buttons.git
##        - git clone https://github.com/tknospdr/force-tag-group-order.git

## Hooks for S3
  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

After a rebuild my site was broken due to a bunch of missing files, so I tried to rake them to the server and got this error for each file:

root@talk-app:/var/www/discourse# rake 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'...
Uploading files to S3...
 - Listing local files
 => 31 files
 - Listing S3 files
. => 4 files
 - Syncing files to S3
#<Thread:0x00007ff89dcbcb20 /var/www/discourse/lib/file_store/to_s3_migration.rb:212 run> terminated with exception (report_on_exception is true):
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/seahorse/client/plugins/raise_response_errors.rb:17:in `call': You can only specify one non-default checksum at a time. (Aws::S3::Errors::InvalidRequest)
    from /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'
    from /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'
    from /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'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/aws-sdk-core/plugins/checksum_algorithm.rb:169:in `call'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/aws-sdk-core/plugins/jsonvalue_converter.rb:16:in `call'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/aws-sdk-core/plugins/invocation_id.rb:16:in `call'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/aws-sdk-core/plugins/idempotency_token.rb:19:in `call'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/aws-sdk-core/plugins/param_converter.rb:26:in `call'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/seahorse/client/plugins/request_callback.rb:89:in `call'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/aws-sdk-core/plugins/response_paging.rb:12:in `call'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/seahorse/client/plugins/response_target.rb:24:in `call'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/aws-sdk-core/plugins/telemetry.rb:39:in `block in call'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/aws-sdk-core/telemetry/no_op.rb:29:in `in_span'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/aws-sdk-core/plugins/telemetry.rb:53:in `span_wrapper'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/aws-sdk-core/plugins/telemetry.rb:39:in `call'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-core-3.226.0/lib/seahorse/client/request.rb:72:in `send_request'
    from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/aws-sdk-s3-1.182.0/lib/aws-sdk-s3/client.rb:17315:in `put_object'
    from /var/www/discourse/lib/file_store/to_s3_migration.rb:215:in `block (2 levels) in migrate_to_s3'

Would love some advice to get this finished up one way or the other.

pfaffman

The missing files are likely assets, so you need the rake task that pushes those to s3 (s3:upload_assets – it’s near the top)

But your errors are likely due to the new aws s3 library breaking a bunch of services. So you’ll need to contrive to downgrade the aws gem or use another service.

I think there may be a topic about how to do that. I’ve done it on a site or two, but am not sure how or where it’s been documented

Lilly

i think it might be this topic

tknospdr

I need to run that even though that’s part of the changes I put in the app.yml file? I thought that was there to automatically push the files during a rebuild.

Just tried it. It’s output was:


root@talk-app:/var/www/discourse# rake s3:upload_assets
Installing CORS rules...
skipping
Skipping: assets/logo-single-3f9a3693.png
Skipping: assets/favicon-7e45025e.ico
Skipping: assets/logo-single-dev-0d38377d.png
Skipping: assets/push-notifications/posted-e02e1c60.png
Skipping: assets/push-notifications/watching_first_post-e02e1c60.png
Skipping: assets/push-notifications/README-d49cc975.md
(big long list...)
Skipping: assets/plugins/footnote_extra-95ffab71.gz.js
pfaffman

You shouldn’t, but those are the things that would make your site be “broken” (or does “broken” mean “images are missing” to you?) Uploading images with migrate_to_s3 just affects images.

I can’t quite explain how the assets were all uploaded already (what was broken on the site? How did those get uploaded if your S3 setup is broken?)

Can you upload any images on your site?

tknospdr

I can’t currently do anything on the site.
Feel free to look at it and see. https://eu.technospider.com

Since everything looks like it’s there in my bucket, there’s probably some env variable that needs to be updated to make everything work right.
If we can crack this we can say R2 is ready for prime time.

pfaffman

This (and a bunch of other files) is missing https://eufiles.technospider.com/extra-locales/ca382c69f8e6b85162b2ba58f2ce100bfe741966/en/mf.js?__ws=eu.technospider.com

Is that your CDN or your bucket? Does that file exist in your bucket? Maybe it’s in your bucket but your CDN is broken?

Here’s how I once configured R2 and I think it worked.

            - "DISCOURSE_S3_REGION: 'auto'"
            - "DISCOURSE_S3_ENDPOINT: https://some-number.r2.cloudflarestorage.com"
            - "DISCOURSE_S3_ACCESS_KEY_ID: 'keyid'"
            - "DISCOURSE_S3_SECRET_ACCESS_KEY: 'secret'"
            - "DISCOURSE_S3_CDN_URL: 'https://r2.myforum.us/xyz'"
            - "DISCOURSE_CDN_URL: 'https://r2.literatecomputing.com'"
            - "DISCOURSE_S3_BUCKET: 'myforum/xyz'"
            - "DISCOURSE_S3_BACKUP_BUCKET: 'myforum/xyz/backups'"

So this never worked?

tknospdr

Where is “extra-locales” supposed to be? I don’t see it under ‘public’ or ‘assets’ even inside the container. Where should I look?

Sorry about the dumb questions, but this is a totally new venture for me.
Is WHAT my CDN or my bucket?

With the leading dashes, and all the single and double quotes? I don’t have any of those in my app.yml file. Should I add those and rebuild to test?
This is exactly how my file looks, indented 2 spaces each:

## This set of lines allows R2 S3 hosted files to be uploaded and downloaded..
  DISCOURSE_CDN_URL: https://eufiles.technospider.com
  DISCOURSE_USE_S3: true
  DISCOURSE_S3_ENDPOINT: https://randomnumber.r2.cloudflarestorage.com
  DISCOURSE_S3_CDN_URL: https://eufiles.technospider.com
  DISCOURSE_S3_BACKUP_BUCKET: exotics-unlimited-backups
  DISCOURSE_INCLUDE_S3_UPLOADS_IN_BACKUPS: true
  DISCOURSE_BACKUP_LOCATION: s3
  DISCOURSE_S3_BUCKET: exotics-unlimited
  DISCOURSE_S3_REGION: auto
  DISCOURSE_S3_ACCESS_KEY_ID: randomnumbers
  DISCOURSE_S3_SECRET_ACCESS_KEY: randomnumbers
  DISCOURSE_S3_INSTALL_CORS_RULE: false

It worked when I had the settings entered via the web UI, then when I put everything into the app.yml file I got what you saw when you went to the site.

pfaffman

Here’s what I see when I access one of your assets:

This object does not exist or is not publicly accessible at this URL. Check the URL of the object that you're looking for or contact the owner to enable Public access.

You can see if https://eufiles.technospider.com/extra-locales/ca382c69f8e6b85162b2ba58f2ce100bfe741966/en/mf.js?__ws=eu.technospider.com works if you change the hostname to your cloudflare endpoint

Can you find that file in your bucket? Can you access it?

Don’t know but that’s a URL I copied from the developer tools in my browser.

So first find that file in your bucket and see if it’s there at all and then you can go about figuring out why the CDN can’t find it.

No. I use a different tool for configuration, but those are the ENV settings that I’m pretty sure worked for me at one time.

I see. That’s frustrating. Good luck.

tknospdr

I get:

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<Code>InvalidArgument</Code>
<Message>Authorization</Message>
</Error>

My endpoint is:
https://7100e60b936991e069a3230dc05d4976.r2.cloudflarestorage.com/exotics-unlimited/

I just changed

DISCOURSE_S3_CDN_URL: https://eufiles.technospider.com

to

DISCOURSE_S3_CDN_URL: https://eufiles.technospider.com/exotics-unlimited

And now I’m faced with a loading throbber that never goes away.
Progress? Who’s to say. :slight_smile:

pfaffman

Find an asset that you can access with the bucket url and then find how to access that same asset via the cdn.

tknospdr

Forgive me for not knowing. But what is the bucket vs the CDN.

Jagster

A bucket is that ”main directory” you’ve created and where all files are. CDN is plenty of servers all around the world and those get copy of that bucket. Your is indentified using the url you gave when that connection was created, as i.e. cdn.example.com.

tknospdr

It seems that with R2 the CDN is automatically created if you give the bucket a custom domain. That was a little confusing as I didn’t have to actually do anything with CDN.

I’ll see what I can figure out.

tknospdr

It seems that no matter what I try, I cannot access any objects from the R2 endpoint URL.

https://7100***********dc05d4976.r2.cloudflarestorage.com/exotics-unlimited/assets/logo-815195ae.png

&

https://exotics-unlimited.7100***********dc05d4976.r2.cloudflarestorage.com/assets/logo-815195ae.png

Gives me:

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<Error>
<Code>InvalidArgument</Code>
<Message>Authorization</Message>
</Error>

But via CDN:

![discourse](upload://4axzzMIqD328iAou0u6qv18Avo8.png)

Gives me:
discourse
Because the error speaks of authorization, I looked into this a bit and came up with this nugget:

Note

By default, only certain file types are cached. To cache all files in your bucket, you must set a Cache Everything page rule.

For more information on default Cache behavior and how to customize it, refer to Default Cache Behavior

From this page:

I created a ‘cache everything’ rule, but no change.

Isambard

Anyone used SeaweedFS? With the uncertainty over MinIO, I’ve been looking at this option and will try it out to see if there are any compatibility issues with Discourse.

tknospdr

I got R2 working correctly by using this set of rules:

  ## This set of lines allows R2 S3 hosted files to be uploaded and downloaded..
  DISCOURSE_USE_S3: true
  DISCOURSE_S3_REGION: auto
  DISCOURSE_S3_ACCESS_KEY_ID: access-key-id
  DISCOURSE_S3_SECRET_ACCESS_KEY: access-key
  DISCOURSE_S3_CDN_URL: https://eufiles.technospider.com
  DISCOURSE_S3_BUCKET: exotics-unlimited
  DISCOURSE_S3_BACKUP_BUCKET: exotics-unlimited-backups
  DISCOURSE_BACKUP_LOCATION: s3
#  DISCOURSE_CDN_URL: https://eufiles.technospider.com
  DISCOURSE_S3_ENDPOINT: https://71*****5d4976.r2.cloudflarestorage.com
#  DISCOURSE_INCLUDE_S3_UPLOADS_IN_BACKUPS: true
  DISCOURSE_S3_INSTALL_CORS_RULE: false

Once I commented out the CDN_URL line things worked. I guess by the nature of the fact that R2 auto creates the CDN you don’t need that line and in fact adding it breaks stuff.
I commented out the include images line just to keep my backup sizes down. I’m using the free tier at R2 and don’t want to go over my limit.

pfaffman

Right. You really don’t want to use DISCOURSE_INCLUDE_S3_UPLOADS_IN_BACKUPS unless you’re moving away from S3. It doesn’t make sense to download all the images from S3 to include them in a backup stored . . . on S3. I once left that enabled on an AWS bucket and had a big bill from downloading every single image every single day.

This is supposed to be a separate CDN that points to your Discourse server, not the S3 bucket. Some stuff, like avatars, and I’m not sure what else, is served from your server. The reason it didn’t work is you included your S3 CDN not the site CDN.

tknospdr

You mean if you use 2 different companies? One for bucket and one for CDN? I’m not well versed on this so I need the info like I’m a 3rd grader…
I know that when you create a “custom domain” in the R2 interface it acts as a CDN so that’s why I initially tried adding that line.

Anyway, it’s been working perfect for my test site and unless there’s something else that it’s supposed to be doing that it’s not I’d recommend the original post be updated to show that Cloudflare now works with Discourse.

pfaffman

No. You can’t do that. There’s only one S3 key/secret. I was trying to contrive a reason to use include s3 uploads, but there is none.

That’s for the S3 Bucket not for your site. There are two different variables DISCOURSE_S3_CDN_URL and DISCOURSE_CDN_URL. You are treating them as if they are the same. You can not use a CDN for the site, but the reason it didn’t work when you set that variable is that you gave it the wrong CDN.

tknospdr

Okay, I thought I had a slight grasp of what I was doing, but now I think I’m completely lost.

So what is the difference between S3 CDN and CDN?

Would it still work if I reversed which of those 2 I’ve commented out?

I noticed an odd issue with the background image of my welcome banner too, is that related at all to any of this?

chapoi

14 posts were split to a new topic: Issues with AWS CDN and S3

decryption128

Hi folks - just letting people know that Hetzner’s object storage seems to work pretty well. These are the settings I added to my app.yaml

DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: whatever
DISCOURSE_S3_INSTALL_CORS_RULE: false
DISCOURSE_S3_ENDPOINT: https://nbg1.your-objectstorage.com
DISCOURSE_S3_ACCESS_KEY_ID: xxxx
DISCOURSE_S3_SECRET_ACCESS_KEY: xxxx
DISCOURSE_S3_CDN_URL: xxxx
DISCOURSE_S3_BUCKET: discourseuploads
DISCOURSE_S3_BACKUP_BUCKET: discoursebackups
DISCOURSE_BACKUP_LOCATION: s3

Obviously, replace the following with your own settings:

DISCOURSE_S3_ENDPOINT: (use the URL from the Hetzner dashboard for the location you made your object storage bucket)
DISCOURSE_S3_ACCESS_KEY_ID: (self-explanatory)
DISCOURSE_S3_SECRET_ACCESS_KEY: (self-explanatory)
DISCOURSE_S3_CDN_URL: (use the CDN URL that pulls from your Hetzner bucket’s URL here)

Will keep an eye on it for the next few weeks/months on my test server, but so far so good.

Lilly

just a note that this is no longer the case - Cloudflare has patched this and R2 buckets are now compatible with S3. i have external backups to Cloudflare R2 and just did a successful full restore to another server. (it’s also free up to 10GB / month)

just need the bucket name (for s3 backup bucket), access key ID, secret access key and jurisdiction-specific endpoint from Cloudflare R2 object storage to put into the Discourse s3 settings or app.yml/web_only.yml etc.

pfaffman

That’s great news! Someone should edit the OP accordingly.

Lilly

i have no idea how the new(ish) doc updating works - apparently they are stored here somewhere? discourse/docs at main · discourse/discourse · GitHub but i don’t see self-hosting docs. :woman_shrugging: nevermind, i see the suggested edits link in the wiki edit page. i will suggest an update.