Using Cloudflare 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)

To use Cloudflare for reverse proxying, make sure that you're logged into your Cloudflare account, and that you've added your domain (called "website" in Cloudflare) to the account.

There are two ways to do this:

  1. Using Cloudflare Workers. This is a bit more setup, but can be used on all Cloudflare plans.
  2. Using DNS and Page Rules. This is simplest method, but requires the Cloudflare Enterprise plan.

Method one: Proxy using Cloudflare Workers

Workers are really powerful and allow up to 100,000 requests per day on the free plan (see Cloudflare pricing). Follow these steps to set up a reverse proxy worker:

1. Create a worker

From the root of the Cloudflare dashboard, go to "Workers & Pages" > "Overview" > "Create application" > "Create Worker". At this point, you can either keep the random worker name or choose your own. Click "Deploy" once done.

2. Configure the worker to act as a proxy

Click "Edit code" once the new worker has been saved following "Deploy". (And if you're already on the worker page, click "Quick edit".) You should now be seeing a code editor for the worker. Just replace all the existing content with this proxying code:

JavaScript
const API_HOST = "us.i.posthog.com" // Change to "eu.i.posthog.com" for the EU region
const ASSET_HOST = "us-assets.i.posthog.com" // Change to "eu-assets.i.posthog.com" for the EU region
async function handleRequest(request, ctx) {
const url = new URL(request.url)
const pathname = url.pathname
const search = url.search
const pathWithParams = pathname + search
if (pathname.startsWith("/static/")) {
return retrieveStatic(request, pathWithParams, ctx)
} else {
return forwardRequest(request, pathWithParams)
}
}
async function retrieveStatic(request, pathname, ctx) {
let response = await caches.default.match(request)
if (!response) {
response = await fetch(`https://${ASSET_HOST}${pathname}`)
ctx.waitUntil(caches.default.put(request, response.clone()))
}
return response
}
async function forwardRequest(request, pathWithSearch) {
const originRequest = new Request(request)
originRequest.headers.delete("cookie")
return await fetch(`https://${API_HOST}${pathWithSearch}`, originRequest)
}
export default {
async fetch(request, env, ctx) {
return handleRequest(request, ctx);
}
};

When done, click "Save and deploy".

3. Use a custom domain for the worker

This step is optional, but highly recommended. To use your own domain instead of the basic *.workers.dev one, go to the worker page (by exiting the code editor, if you're still in it) and there click "settings" -> "triggers". Click "Add Custom Domain", type in a subdomain, and save with "Add Custom Domain". The subdomain can be anything, even pineapple.yourdomain.com – just remember to avoid terms like "tracking" or "analytics", as they may be blanket-blocked.

4. Use the new host in SDKs

You can now use your worker's domain (shown under "Preview" on the worker page) as api_host in PostHog SDKs! If you've added a custom domain in step 3, use that instead. Make sure to set the ui_host to your actual PostHog app URL (e.g. us.posthog.com).

Method two: Proxy using DNS and Page Rules with Cloudflare Enterprise

Proxying traffic using DNS is relatively straight-forward. However, it requires correcting the Host headers for proxied requests, which is only available on the Cloudflare Enterprise plan. If your domain is on this plan, follow these steps:

1. Add a DNS record

Select your website in the Cloudflare dashboard, go to the "DNS" page, and there click "Add record". Make sure this is a CNAME record, and choose a name for it, which will be the PostHog proxy subdomain. The subdomain can be anything, even watermelon.yourdomain.com – just remember to avoid terms like "tracking" or "analytics", as they may be blanket-blocked. The record should point to us-proxy-direct.i.posthog.com or eu-proxy-direct.i.posthog.com (depending on your PostHog region), and have proxy enabled (e.g. CNAME, e, us-proxy-direct.i.posthog.com, proxied).

2. Correct Host headers

The proxy won't work if the Host headers of requests aren't rewritten from your domain to the PostHog domain. To fix this, add a Page Rules to change the Host header to us-proxy-direct.i.posthog.com or eu-proxy-direct.i.posthog.com (depending on your PostHog region).

3. Use the new host in SDKs

You can now use your CNAME record's domain as api_host in PostHog SDKs! Make sure to set the ui_host to your actual PostHog app URL (e.g. us.posthog.com) as well.

Questions?

Was this page useful?

Next article

Using Netlify redirects as a reverse proxy

Netlify supports redirects and rewrites which we can use as a reverse proxy from an /ingest route. In your netlify.toml file, add a redirect like this: Note: This proxy configuration works with custom domains but may not work correctly with the default .netlify.app domain. If you're experiencing issues with PostHog requests being blocked, ensure you're using a custom domain rather than the default Netlify domain. Once done, set the /ingest route of your domain as the API host in your…

Read next article