Setting up AWS CloudFront as a reverse proxy

Last updated:

|Edit this page

Note: The following self-hosted proxy isn't provided by PostHog, so we can't take responsibility for it! If unsure, we recommend using our managed reverse proxy.

Note: If you are using the EU cloud then use eu instead of us in all domains (e.g. us.i.posthog.com -> eu.i.posthog.com)

CloudFront can be used as a reverse proxy. Although there are multiple other options if you're using AWS.

By default, CloudFront doesn't forward headers, cookies, or query parameters received from the origin that PostHog uses. To set these up, you need an "origin request policy" as in the instructions below.

Create a distribution

  1. On the AWS dashboard, search for CloudFront, then create a new CloudFront distribution
  2. Set the origin domain to your PostHog instance us.i.posthog.com or eu.i.posthog.com for PostHog Cloud).
  3. Select HTTPS only.
  4. Under Default cache behavior, go to Viewer. “Under Allowed HTTP methods,” select “GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE,” and check OPTIONS under “Cache HTTP methods.” This allows all HTTP methods.
  5. Under Cache policy, click “Create policy.” On the “Create cache policy” page:
    1. Name your policy “origin-cors.”
    2. Scroll to “Cache key settings,” click the dropdown for “Headers” that says “Include the following headers,” select Origin and Authorization.
    3. Under “Query strings,” select “All.”
    4. Click “Create” at bottom of the page.
a screenshot of the cloudfront cache policy settings
  1. Back on the “Create distribution” page, select your “origin-cors” cache policy.
  2. Under “Origin request policy,” choose “CORS-CustomOrigin.”
  3. Under “Response headers policy,” choose “CORS-with-preflight-and-SecurityHeadersPolicy.”
  4. Do not enable AWS Web Application Firewall (WAF).
  5. Click “Create distribution” at bottom of the page.
  6. Edit the Cloudfront Distribution and add the assets origin us-assets.i.posthog.com or eu-assets.i.posthog.com.
  7. Add another behavior the path will be /static/*.
  8. Under "Origin,", choose the one created above.
  9. Under “cache policy,” choose “origin-cors”
  10. Under “Origin request policy,” choose “CORS-CustomOrigin.”
  11. Under “Response headers policy,” choose “CORS-with-preflight-and-SecurityHeadersPolicy.”

Once created, copy the distribution domain name, and set it as your API host in your PostHog initialization like this:

JavaScript
posthog.init('<ph_project_api_key>',
{
api_host: 'https://<distribution_domain_name>.cloudfront.net',
ui_host: '<ph_app_host>'
}
)

You can find out about CloudFront pricing on the AWS website.

Setup video

Questions? Ask Max AI.

It's easier than reading through 555 docs articles.

Community questions

  • Mark
    a month ago

    How ad-blockers dont block CloudFront endpoint request

    HI Team, As I understood, the ad-blockers basically blocks any request if it doesnt match with the current domain. Eg: my domain is xyz.com.au. When my site renders and need to push analytical data to PostHog, it may be blocked by ad-blocker.

    As you mentioned, If we introduce AWS CloudFront, still the domain name is not match with my domain. The cloudFront end point is like

    blahblah.cloudfront.net

    How does this work?

    • Rafael(he/him)
      a month agoSolution

      Hey, Mark!

      It doesn't block "any request that doesn't match the current domain", it attempts to block domains that are known to be ad-related. In this case, many adblockers decided to block any *.posthog.com subdomain even though we're not really serving any ads - some people do think analytics are bad, and that's why they block us. On the other hand, adblockers won't be blocking *.cloudfront.net subdomains because they risk blocking required functionality, as CloudFront is not used for ad/analytics-only, it's used to power the whole internet.

      Let me know if this isn't clear for you yet!

  • Benjamin
    a month ago

    301 Moved Permanently

    If you happen to get 301 Moved Permanently response, check that you didn't make a mistake on your origin protocol policy. I had set "http-only" instead of "https-only".

    Hope this will help someone :)

  • Alex
    3 months ago

    CORS issue

    Hi,

    I set everything up per the instructions, but I'm getting the following error:

    Access to XMLHttpRequest at 'https://ph.alexperelman.com/array/phc_GLjclqTGwS3YNW1GFEPWeAXTKvulDYH5pAc2BF96H55/config?ip=1&_=1734490174934&ver=1.201.1' from origin 'https://alexperelman.com' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

    • Post
      3 months agoSolution

      I got it 'fixed' with the above XMLHttpRequest credentials mode function. Maybe a smarter person could explain why we are getting the error in the first place now.

      (function (open, send) {
      XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
      this._isPostHogRequest = url.includes('[distribution].cloudfront.net');
      open.apply(this, arguments);
      };
      XMLHttpRequest.prototype.send = function () {
      if (this._isPostHogRequest) {
      this.withCredentials = false;
      }
      send.apply(this, arguments);
      };
      })(XMLHttpRequest.prototype.open, XMLHttpRequest.prototype.send);
  • Simon
    8 months ago

    behvaiour for /static/*

    Why do I need to add behaviour for /static/* if it is same as default behaviour?

    Even in video it is not shown

    • Ben
      8 months agoSolution

      It's not the same. The /static/ configuration should point to the "assets" domain e.g. us-assets.i.posthog.com so that it is appropriately hitting a highly cached CDN rather than our main ingestion domains.

      It isn't mentioned in the video as the video is a little outdated.

    • Simon
      Author8 months ago

      Thanks for explaining I did not notice it was different domain.

  • Vincent
    10 months ago

    Recorder not working after proxy set up

    After I set this up, all other activities are properly recorded, but the screen recording stopped working. Found a 404 in this link:

    https://_.cloudfront.net/login?next=/static/%2A/static/recorder.js%3Fv%3D1.131.3

    • Vincent
      Author10 months ago

      Hi sorry, I fixed it by removing origin path for assets and invalidating cloudfront cache. Thanks.

  • fabienne
    a year ago

    till getting a POST https://eu.i.posthog.com/ ERR_BLOCKED_BY_CLIENT with ad blocker

    Hello,

    Thanks for the very clear instructions. We have followed them but we are still looking for some help to set it up properly in the front-end. In my Posthog init, I am using

    When doing so, I am still getting an ERR_BLOCKED_BY_CLIENT on the following request POST https://eu.i.posthog.com/ when using an ad blocker.

    Is there someone I could contact to get some help?

    thanks a lot

    Fab

    • mahendra
      10 months ago

      So I actively worked with Fabienne to get this to work with CloudFront Reverse Proxy directly in production now, with the PostHog reverse proxy setup (and we managed to terraform it too), looks like some of the document is disconnected with the video, etc... anyways here is how I made it work, I used

      ui_host domain_name = "eu.i.posthog.com" for europe ## it would not work for domain_name = "eu.posthog.com" OR "eu-assets.i.posthog.com" i.e Step 11

      origin_id = "eu.i.posthog.com" for europe ## it would not work for origin_id = "eu.posthog.com"

      Also when setting origin_path = "/static/*" it would not work too i.e Step 12

      So it looks like Step 11 and 12 are not needed?

Was this page useful?

Next article

Setting up Caddy as a reverse proxy

Caddy makes setting up a reverse proxy with TLS simple. For these examples: Sub out YOUR_TRACKING_DOMAIN for the domain you use for proxying to PostHog. We'd suggest something like e.yourdomain.com . Make sure your DNS records point to the server where Caddy is running. Make sure ports 80 and 443 are open and directed toward Caddy. Basic setup First, install Caddy . Next, create a Caddyfile that listens for incoming requests and proxies them to PostHog: Run caddy start from the same…

Read next article

PostHog.com doesn't use third party cookies - only a single in-house cookie.

No data is sent to a third party.

Ursula von der Leyen, President of the European Commission