Full Site CDN Using AWS CloudFront

Hello All. I recently got my Discourse installation setup using AWS CloudFront (CF) for full site acceleration - and SSL offloading using AWS certs in CF. Note that this installation deviates from the official guide regarding CDN and SSL configuration - so that might be controversial and lead to future supportability issues. So be forewarned… there be dragons here. I am sharing the configuration that worked for me here:

  1. Setup discourse to listen on port 80 only and disable Let’s Encrypt by commenting out the indicated lines in app.yml:

  2. Setup discourse to pay attention to the CF header, cloudfront-forwarded-proto, rather than x-forwarded-proto (which CF does not pass - and strangely can’t be configured to pass to origin… nuts! :angry:)

  3. Setup your CF distribution with a cname for your intended public hostname (e.g. forum.example.com) using an AWS ACM certificate (that you generated).

  4. Setup the CF origin using the public elastic IP of the EC2 server hosting discourse (e.g. ec2-xxx-xxx-xxx-xxx.compute-1.amazonaws.com). configure it for http only (i.e. just port 80 - no 443). you do not need to setup your origin with a fancy hostname in DNS like forum-origin.example.com. The ec2 hostname or IP works fine.

  5. Setup the CF “behaviors” for the different request paths. The key here is to configure caching behavior for things that are obviously static resources; and configure no-caching for everything else (i.e. those requests are just passed through as-is to the origin with no caching). Another key thing here is that that last pass-though rule (“default”) is using a custom “origin request policy” that passes all original headers through to the origin in addition to the CF cloudfront-forwarded-proto header. Also configure http to https redirects in your behaviors - so that all end user requests are forced to be https by CF.

  6. Do not configure “DISCOURSE_CDN_URL”

  7. Do enable “force https”

  8. Do not configure “long polling base url” - leave it blank. Despite all dire warnings about this being troublesome when passing it through a proxy, it’s working just fine for me so far. Maybe CF’s default keep alive is long enough to prevent it from dropping the connection.

I think that’s it… :thinking:

The end result is that all requests, http/documents, all supporting static resources, all ajax calls, etc. are all serviced on the same domain name (e.g. forum.example.com). Caching behavior (and pass-through behavior) is dictated by your “behaviors” configured in CF. And all connections are encrypted using AWS ACM certs terminated on the CF edge - and then unencrypted/http traffic is sent back to the origin server.

I dare say this might be cleaner than what meta.discourse.org has going on right now :shushing_face:.

6 Likes

Hi @jaffadog

I’m in the similar scenario but in full site with a different CDN. In your experiment, did you ever test config DISCOURSE_CDN_URL with the website domain URL. For example, in full CDN mode, if your website URL is https://foo.bar.com; then the CDN URL should be https://foo.bar.com as well. If we leave DISCOURSE_CDN_URL empty then website assets url will start with relative path. For example as below snippet,

      <link rel="preload" href="/extra-locales/admin?v=8f522e122c802d1ed66dfa7fecafbb35" as="script">
<script defer src="/extra-locales/admin?v=8f522e122c802d1ed66dfa7fecafbb35"></script>

This just looks not elegant in a production website, though both URL make request to https://foo.bar.com.