Configuring Cloudfront for Subfolder

This topic is a companion to another, which focuses on the Discourse configuration. Here we will set up a Cloudfront distribution as the reverse proxy before Discourse.

:warning: The only time you need this combination is when you already have a Cloudfront distribution for the primary hostname and would like to proxy a subfolder to a Discourse forum. This guide assumes the reader to have previous experience using Cloudfront in production.

Flow of Traffic

When a user loads the site there are two network connections involved. Each has a different hostname:

  • The web browser will issue a request to Cloudfront for the public hostname.
  • Then Cloudfront will issue a request to the Discourse servers for the origin hostname.
 .───────.      .───────.      .─────────.
( browser )───▶(   CF    )───▶( discourse )
 `───────'      `───────'      `─────────'

For our example, we’re going to pretend your Discourse site will load from https://www.example.com/forum/, using:

purpose hostname
public hostname www.example.com
origin hostname discourse.example.com

Cloudfront Setup

This means there will be at least two origins defined – a default for the primary site and a second for the Discourse servers.

There will also be at least two behaviors, one pointing to each origin.

The default behavior and origin are not relevant for our purposes here; it must already be configured as appropriate to your needs. The Discourse-specific origin and behavior should be configured as follows.

Origin

The second origin for the Discourse servers should be pointed at the origin hostname.

Do not configure an origin path.

The protocol policy should be HTTPS, with TLSv1 as the minimum version.

Behavior

The pattern needs to match the subfolder.

It should be attached to the origin configured as above.

It should redirect HTTP → HTTPS.

image

It should permit all HTTP verbs.

It should disable caching.

It should forward all client headers.

Configuring Lambda@edge

Shared hosting environments (including discourse.org) use SNI. To make this work with Cloudfront, you’ll need to use Lambda@edge to make sure that Cloudfront uses the origin hostname for SNI, rather than the Host header from the viewer’s request.

Visit the AWS Lambda dashboard and create a new function. Use the Node.js runtime environment, and create a new role with “Basic Lambda@Edge permissions”:

Click “Create Function”

Once the code editor appears, replace the example with this:

exports.handler = async (event, context) => {
    const request = event.Records[0].cf.request;
    request.headers['x-forwarded-host'] = [{
        key: 'x-forwarded-host',
        value: request.headers['host'][0]['value']
    }];
    request.headers["host"] = [{
        key: 'host',
        value: request.origin.custom.domainName
    }];
    return request;
};

Click “Deploy”.

In the top left, choose Actions → Deploy to Lambda@Edge

Choose your Cloudfront distribution, and select the correct Behavior from the list:

If you need to make changes for any reason, make sure to “Deploy”, then “Publish new Version” from the versions tab, then update your distribution to use the new version of the Lambda.

9 Likes