AWS CloudFront reverse proxy

Before you start
  • If you use a self-hosted proxy, PostHog can't help troubleshoot. Use our managed reverse proxy if you want support.
  • Use domains matching your PostHog region: us.i.posthog.com for US, eu.i.posthog.com for EU.
  • Don't use obvious path names like /analytics, /tracking, /telemetry, or /posthog. Blockers will catch them. Use something unique to your app instead.

This guide shows you how to configure AWS CloudFront as a reverse proxy for PostHog.

Why CloudFront needs custom configuration

CloudFront's default settings don't forward the headers, cookies, and query parameters PostHog needs to function. Without custom cache and origin request policies:

  • Events will fail to authenticate due to missing Authorization headers
  • CORS requests will be blocked due to missing Origin headers
  • Feature flags and session recording won't work correctly due to stripped query parameters

You'll need to create custom policies to ensure CloudFront passes everything through to PostHog.

Architecture overview

Your CloudFront distribution will route two types of requests:

  • Event and API requests: Routes to your main origin, us.i.posthog.com or eu.i.posthog.com. This handles event capture, feature flags, session recordings, and all PostHog API calls.
  • Static assets: Routes to your assets origin, us-assets.i.posthog.com or eu-assets.i.posthog.com. This serves PostHog's JavaScript SDK and other static files.

CloudFront uses "behaviors" to route requests. The /static/* behavior routes to your assets origin, while the default behavior routes everything else to your main origin.

Set up your CloudFront proxy

  1. Create a CloudFront distribution

    In the CloudFront console, follow AWS's guide to create a CloudFront distribution.

    Configure these CloudFront settings for your origin:

    Origin settings:

    • Origin domain: us.i.posthog.com or eu.i.posthog.com
    • Protocol: HTTPS only

    This tells CloudFront to forward requests to PostHog's ingestion endpoint. HTTPS only ensures all traffic is encrypted.

    Default cache behavior:

    • Allowed HTTP methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
    • Cache HTTP methods: Check OPTIONS

    PostHog needs all HTTP methods because you'll capture events (POST), retrieve feature flags (GET), and handle CORS preflight requests (OPTIONS).

  2. Create a custom cache policy

    In the CloudFront console, follow AWS's guide to create a cache policy.

    Configure this custom policy:

    • Name: posthog-cache-policy or any name you prefer
    • Headers: Include Origin and Authorization
    • Query strings: All

    This policy tells CloudFront to include these values when caching responses. Without this, CloudFront would strip authentication headers and break event capture.

  3. Apply your custom cache policy

    In the CloudFront console, edit your distribution's default cache behavior.

    Apply these CloudFront policies:

    • Cache policy: Your custom posthog-cache-policy from step 2
    • Origin request policy: CORS-CustomOrigin

    The CORS-CustomOrigin policy is built into AWS and forwards CORS-related headers to your origin. You don't need to create it.

    Leave AWS WAF disabled for now. If you enable it later, make sure its size limit is at least 1MB for events and 64MB for session recordings. AWS WAF defaults to 8KB, which will block PostHog traffic.

  4. Add a second origin for static assets

    In the CloudFront console, add a second origin to your distribution.

    Configure this origin:

    • Origin domain: us-assets.i.posthog.com or eu-assets.i.posthog.com

    This origin serves PostHog's JavaScript SDK and other static files. Separating static assets from API requests allows different caching strategies.

  5. Create a custom origin request policy

    In the CloudFront console, follow AWS's guide to create an origin request policy.

    Configure this custom policy:

    • Name: posthog-origin-request-policy or any name you prefer
    • Headers: Include Origin
    • Query strings: All

    Origin request policies control what CloudFront sends to your origin, regardless of caching. This ensures PostHog receives all headers and query parameters it needs.

  6. Create a cache behavior for static assets

    In the CloudFront console, add a new cache behavior to your distribution.

    Configure this CloudFront behavior:

    • Path pattern: /static/*
    • Origin: Your assets origin, us-assets.i.posthog.com or eu-assets.i.posthog.com
    • Cache policy: Your custom posthog-cache-policy from step 2
    • Origin request policy: Your custom posthog-origin-request-policy from step 5
    • Response headers policy: CORS-with-preflight-and-SecurityHeadersPolicy

    This behavior routes requests to /static/* to your assets origin instead of the main origin. The response headers policy is built into AWS and adds CORS headers to responses.

    If you encounter CORS errors after setup, you may need to create a custom response headers policy with Access-Control-Allow-Headers set to * for all headers. See AWS's CORS troubleshooting guide for details.

  7. Update your PostHog SDK

    In your application code, update your PostHog initialization to use your CloudFront distribution domain:

    posthog.init('<ph_project_api_key>', {
    api_host: 'https://d111111abcdef8.cloudfront.net',
    ui_host: 'https://us.posthog.com'
    })

    Replace d111111abcdef8.cloudfront.net with your actual CloudFront distribution domain. Find this in the CloudFront console under distribution domain name.

    The ui_host must point to PostHog's actual domain so features like the toolbar link correctly.

  8. Verify your setup

    Checkpoint

    Confirm events are flowing through CloudFront:

    1. Open your browser's developer tools and go to the Network tab
    2. Trigger an event in your app, like a page view
    3. Look for a request to your CloudFront domain
    4. Verify the response is 200 OK, not 403 Forbidden or 400 Bad Request
    5. Check the PostHog app to confirm events appear

    If you see 403 errors, your cache or origin request policies aren't forwarding required headers. Double-check your policy configurations.

Troubleshooting

403 Forbidden errors

If CloudFront returns 403 Forbidden when capturing events:

  1. Verify your cache policy includes Authorization and Origin headers
  2. Check that your origin request policy forwards all query strings
  3. Confirm you're using the CORS-CustomOrigin origin request policy on your default behavior

CloudFront blocks requests when required headers are missing. The Authorization header is essential for PostHog to authenticate your events.

CORS errors in browser console

If you see CORS errors like No 'Access-Control-Allow-Origin' header:

  1. Verify you applied the CORS-with-preflight-and-SecurityHeadersPolicy response headers policy to your /static/* behavior
  2. Check that your cache policy includes the Origin header
  3. If errors persist, create a custom response headers policy with Access-Control-Allow-Headers set to *

See AWS's CORS troubleshooting guide for more details.

Events or recordings are being truncated

If large events or session recordings aren't reaching PostHog:

  1. Check if you enabled AWS WAF on your distribution
  2. If enabled, verify the WAF body size limit is at least 64MB
  3. AWS WAF defaults to 8KB, which will block PostHog traffic

PostHog events can be up to 1MB and session recordings up to 64MB per message. Any size limit below these values will silently drop data.

Static assets aren't loading

If the PostHog SDK fails to load or you see 404 errors for /static/* requests:

  1. Verify you created a second origin pointing to us-assets.i.posthog.com or eu-assets.i.posthog.com
  2. Confirm you created a cache behavior with path pattern /static/* pointing to this origin
  3. Check that the assets origin matches your PostHog region (US or EU)

Without the /static/* behavior, CloudFront tries to serve static files from your main origin, which will fail.

Community questions

Was this page useful?

Questions about this page? or post a community question.