Skip to content

Commit 1a370ed

Browse files
fix: update CloudFront reverse proxy to use AllViewerExceptHostHeader (#5614)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 2d7953b commit 1a370ed

1 file changed

Lines changed: 35 additions & 11 deletions

File tree

fern/products/docs/pages/preview-publish/reverse-proxy.mdx

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,28 +82,49 @@ The Worker forwards Fern's `Cache-Control` header, so caching works automaticall
8282
<Steps>
8383
<Step title="Add a Fern origin">
8484

85-
Add an origin to your CloudFront distribution pointing to `app.buildwithfern.com` (HTTPS only, port 443). Add a custom origin header:
85+
In your CloudFront distribution, go to **Origins** and create a new origin:
86+
87+
| Setting | Value |
88+
|---|---|
89+
| **Origin domain** | `app.buildwithfern.com` |
90+
| **Protocol** | HTTPS only |
91+
| **HTTPS port** | 443 |
92+
| **Minimum origin SSL protocol** | TLSv1.2 |
93+
94+
Under **Add custom header**, add:
8695

8796
| Header name | Value |
8897
|---|---|
8998
| `x-fern-host` | `mydomain.com` |
9099

91-
CloudFront automatically sets the `Host` header to the origin domain.
100+
Replace `mydomain.com` with your bare domain (without the subpath).
92101
</Step>
93-
<Step title="Create a cache behavior for `/docs*`">
102+
<Step title="Create a cache behavior for your docs path">
103+
104+
Go to **Behaviors** and create a new behavior:
105+
106+
| Setting | Value |
107+
|---|---|
108+
| **Path pattern** | `/docs*` |
109+
| **Origin** | The Fern origin you just created |
110+
| **Viewer protocol policy** | Redirect HTTP to HTTPS |
111+
| **Cache policy** | `CachingDisabled` (AWS managed) |
112+
| **Origin request policy** | `AllViewerExceptHostHeader` (AWS managed) |
94113

95-
Set the behavior to:
114+
`AllViewerExceptHostHeader` forwards all viewer headers, query strings, and cookies to the origin while letting CloudFront set the `Host` header to `app.buildwithfern.com`. This is required — Fern's origin uses the `Host` header for routing and rejects requests with an unrecognized host.
96115

97-
- **Origin**: the Fern origin you just created
98-
- **Cache policy**: `CachingDisabled` (AWS managed policy)
99-
- **Origin request policy**: `AllViewer` (forwards all headers, query strings, and cookies)
116+
<Warning>
117+
Do not use the `AllViewer` origin request policy. It forwards the viewer's `Host` header (your domain) instead of the origin's, which causes Fern's origin to return errors or raw React Server Component payloads instead of HTML.
118+
</Warning>
119+
</Step>
120+
<Step title="Verify the behavior order">
100121

101-
To use a custom cache policy instead of `CachingDisabled`, set min, max, and default TTL to `0` and forward `Host` and `x-fern-host`.
122+
CloudFront evaluates behaviors in order. Ensure your `/docs*` behavior appears **above** the default (`*`) behavior so docs requests are routed to Fern's origin rather than your primary site.
102123
</Step>
103124
</Steps>
104125

105126
<Warning>
106-
CloudFront ignores `CDN-Cache-Control` and `Surrogate-Control` — only the standard `Cache-Control` header is read. A custom cache policy with a non-zero default TTL caches responses regardless of Fern's `Cache-Control: max-age=0` directive.
127+
CloudFront ignores `CDN-Cache-Control` and `Surrogate-Control` — only the standard `Cache-Control` header is read. If you use a custom cache policy instead of `CachingDisabled`, set the default, minimum, and maximum TTL to `0`. A non-zero default TTL caches HTML responses regardless of Fern's `Cache-Control: max-age=0` directive, which can cause stale content and errors.
107128
</Warning>
108129
</Accordion>
109130

@@ -256,8 +277,9 @@ Caddy doesn't cache responses by default, so no extra caching configuration is n
256277
Run these checks against your live subpath:
257278

258279
```bash
259-
# Check that the page loads and x-fern-host is recognized
260-
curl -sI https://mydomain.com/docs | head -20
280+
# Confirm the page returns HTML (not an error or RSC payload)
281+
curl -sI https://mydomain.com/docs | grep -i content-type
282+
# Expected: content-type: text/html; charset=utf-8
261283

262284
# Verify Cache-Control on the HTML response
263285
curl -sI https://mydomain.com/docs | grep -i cache-control
@@ -267,4 +289,6 @@ curl -sI https://mydomain.com/docs | grep -i cache-control
267289
curl -sI https://mydomain.com/docs | grep -i "^age:"
268290
```
269291

292+
If `content-type` is `text/x-component` instead of `text/html`, your proxy is forwarding the viewer's `Host` header to Fern's origin. Ensure the `Host` header sent to the origin is `app.buildwithfern.com`.
293+
270294
If the `age` header is present and non-zero, your proxy is serving a cached response. Revisit your provider's configuration to ensure HTML caching is disabled.

0 commit comments

Comments
 (0)