Troubleshooting S3 Uploads: Site hangs after rebuild, JS assets fail to load with net::ERR_... on both R2 and GCS

Hello Discourse Team and Community,

I’ve been trying to configure my self-hosted Discourse instance to use an external S3-compatible object storage, but I’ve run into a very persistent and unusual issue. I would be very grateful for any help.

My Environment:

  • Discourse Version: Standard Docker install, latest tests-passed.

  • Host: [YOUR VPS PROVIDER and OS] (请在这里填入您的服务商和系统)

  • Reverse Proxy: Caddy

Goal: My goal is to move all uploads (user uploads and site assets) from local storage to an external provider.

Problem Summary: After configuring app.yml for S3 (either Cloudflare R2 or Google Cloud Storage) and running ./launcher rebuild app, the site hangs on the initial loading screen (the blue spinner). The browser’s developer tools show that most core JavaScript assets fail to load from the external CDN URL with a generic network error (net::ERR_...).

Debugging Steps Taken:

  1. Attempt with Cloudflare R2:

    • I configured a Cloudflare R2 bucket, created an API Token (Object Read & Write), and connected a custom domain (s3.ryzelan.sbs) via Cloudflare DNS.

    • I configured app.yml with the R2 credentials, the custom domain as the endpoint/CDN URL, and set DISCOURSE_FORCE_HTTPS: true and DISCOURSE_S3_FORCE_PATH_STYLE: true.

  2. Crucial Test - Switching to Google Cloud Storage:

    • To rule out a Cloudflare-specific issue, I reverted all changes and did a fresh setup with Google Cloud Storage using S3 interoperability keys.

    • After rebuilding with the GCS configuration, I encountered the exact same JavaScript loading failure pattern as with R2.

Current Status:

  • The ./launcher rebuild app process completes without any errors displayed in the terminal.

  • The app container is running correctly after the rebuild (verified with docker ps).

  • The ./launcher logs app command shows no errors; all internal services (unicorn, redis, postgres) appear to be running normally.

  • The problem seems to be a network-level failure when the browser tries to fetch JS assets from the configured external CDN URL, and this happens regardless of which provider (R2 or GCS) is used.

Here is the final app.yml configuration block we used for R2 (the GCS one was similar):

— Cloudflare R2 S3 Configuration START (Final Version) —

DISCOURSE_FORCE_HTTPS: true
DISCOURSE_USE_S3: true
DISCOURSE_S3_REGION: “us-east-1”
DISCOURSE_S3_ENDPOINT: “https://s3.ryzelan.sbs
DISCOURSE_S3_CDN_URL: “https://s3.ryzelan.sbs
DISCOURSE_S3_ACCESS_KEY_ID: “REDACTED”
DISCOURSE_S3_SECRET_ACCESS_KEY: “REDACTED”
DISCOURSE_S3_BUCKET: “ryzelan-discourse”
DISCOURSE_S3_FORCE_PATH_STYLE: true

— Cloudflare R2 S3 Configuration END —

My Question: What could cause a fresh Discourse rebuild to consistently fail to load its own assets from two different, major cloud providers with a network error? Is there a known issue with certain VPS networking environments, Docker networking, or Caddy that could be causing this?

Thank you for your time and any insights you can provide.

Did you include bit to upload those assets to S3?

If you don’t do that, none of the assets are on S3 and the site won’t load.