Staticbot logoStaticbot.dev

    Deploy a PostHog Reverse Proxy on AWS CloudFront — The Easy Way

    Ad blockers strip 10-30% of your analytics data. A reverse proxy fixes that by routing PostHog events through your own domain. Here's why it matters, what usually goes wrong, and how Staticbot deploys it for you in minutes.

    Published March 26, 2026
    7 min read

    This article is for developers and engineering teams using PostHog for product analytics who want more accurate data without maintaining complex cloud infrastructure by hand. We cover the benefits of reverse proxying, common deployment pitfalls, and how Staticbot automates the entire setup on your own AWS account.

    The Ad Blocker Problem

    Browser ad blockers maintain lists of known analytics domains. When your frontend sends events directly to eu.i.posthog.com or us.i.posthog.com, a significant chunk of those requests never reach PostHog. They're silently blocked before the browser even makes the connection.

    The result: your product analytics are incomplete. Feature flag evaluations don't run. Session recordings have gaps. You're making decisions based on data that systematically excludes a segment of your users — often the more privacy-conscious, technically savvy ones whose behavior you'd most want to understand.

    PostHog estimates that a reverse proxy increases event capture by 10-30%, depending on your user base.

    How a Reverse Proxy Fixes It

    A reverse proxy sits between your users and PostHog. Instead of sending analytics events to eu.i.posthog.com, your frontend sends them to a subdomain you control — like e.yourdomain.com. That subdomain forwards everything to PostHog behind the scenes.

    Ad blockers haven't cataloged your domain, so the requests go through. From PostHog's perspective, nothing changes — it receives the same events, the same way. From your users' perspective, everything is first-party traffic on your own domain.

    More Accurate Data

    Capture events from users running ad blockers. No silent data loss, no blind spots in your analytics.

    First-Party Traffic

    Events appear as first-party requests to your own domain. No third-party cookies, no cross-origin complexity.

    Feature Flags Work

    Feature flag evaluations, session recordings, and experiments all depend on reliable event delivery.

    Why AWS CloudFront?

    PostHog offers a managed reverse proxy that handles everything for you. It's the simplest option and works well for most teams. But there are reasons you might want your own:

    • Your AWS account, your infrastructure. The proxy runs in your account. You control the billing, the access policies, the deployment lifecycle. Nothing is shared.
    • DNS uncloaking resistance. Some privacy-focused DNS resolvers (like NextDNS or Pi-hole) follow CNAME chains to detect analytics proxies. A CloudFront distribution with your own ACM certificate doesn't have a CNAME chain that resolves to PostHog.
    • Cloudflare Enterprise zone holds. If you use Cloudflare with zone holds enabled, PostHog's managed proxy can't provision SSL certificates for your domain. A self-hosted CloudFront proxy avoids this entirely.
    • Custom cache and CORS policies. You control the exact cache behavior, origin request headers, and CORS configuration. No guessing what the managed proxy does under the hood.

    What Makes CloudFront Setup Hard

    PostHog's CloudFront proxy guide walks through a 7-step manual setup: create a distribution, configure two origins, build custom cache and origin request policies, set up a static assets behavior, wire up CORS. It works, but there are sharp edges at every step.

    Host header forwarding

    If your origin request policy forwards all viewer headers, CloudFront sends Host: yourdomain.com to PostHog instead of Host: eu.i.posthog.com. PostHog returns 404 for every request. The fix is to whitelist specific headers, not forward all of them — but this isn't obvious from the AWS console.

    Cache policy constraints

    When you disable caching (TTL=0), CloudFront requires cookie, header, and query string behaviors to be set to "none." If you set them to "all" or "whitelist," the API returns a cryptic InvalidArgument: CookieBehavior is invalid for policy with caching disabled error.

    CORS with credentials

    Using Access-Control-Allow-Headers: * with Access-Control-Allow-Credentials: true violates the CORS spec. CloudFront rejects the policy creation. You need to list each header individually.

    ACM certificates and Route53

    CloudFront requires ACM certificates in us-east-1 — regardless of your distribution's region. If you already have a hosted zone or wildcard certificate in your account, you want to reuse them rather than creating duplicates. Getting this right with Terraform requires conditional logic.

    Root domain misuse

    Deploying a reverse proxy on a root domain (like example.com) instead of a subdomain (like e.example.com) overwrites existing DNS records. If your website lives on that domain, it goes down.

    How Staticbot Deploys It for You

    Staticbot's proxy deployment wizard handles the entire CloudFront setup through a simple form. You pick your PostHog region (US or EU), optionally choose a custom domain, and hit deploy. The rest is automated.

    1

    Pre-deployment checks

    Before touching any infrastructure, Staticbot assumes a cross-account IAM role into your AWS account and checks for existing Route53 hosted zones and ACM certificates. If a wildcard certificate for your domain already exists, it reuses it. If a hosted zone exists, it reuses that too. No duplicate resources, no conflicts.

    2

    Domain validation

    The wizard prevents you from deploying on a root domain. If you type example.com, it tells you to use a subdomain like e.example.com instead. This validation runs both in the frontend form and in the backend API — you can't accidentally overwrite your website's DNS records.

    3

    Terraform on your account

    The deployment runs OpenTofu (open-source Terraform) against your AWS account. It creates the CloudFront distribution with both origins (API and static assets), custom cache and origin request policies, CORS headers, and optionally an ACM certificate with DNS validation and a Route53 alias record — all with the correct configuration that avoids the pitfalls described above.

    4

    Your infrastructure, fully managed state

    The Terraform state is stored in an S3 bucket in your account with DynamoDB locking. You can inspect, modify, or take over the infrastructure at any time. Staticbot doesn't lock you into anything — it's a deployment tool, not a hosting platform.

    What Gets Created in Your AWS Account

    After deployment, your account contains:

    ResourcePurpose
    CloudFront DistributionThe proxy itself — routes API requests and /static/* to PostHog's origins
    Cache PolicyDisables caching (TTL=0) so events are forwarded in real time
    Origin Request PolicyWhitelists CORS headers without forwarding Host (which breaks PostHog)
    Response Headers PolicyCORS headers with credentials support and correct header enumeration
    ACM CertificateSSL certificate for your custom domain (us-east-1, DNS-validated) — or reuses an existing one
    Route53 A RecordAlias record pointing your subdomain to the CloudFront distribution

    If you skip the custom domain, only the CloudFront distribution and its policies are created. You'll get a *.cloudfront.net URL that works immediately.

    Updating Your PostHog SDK

    Once deployed, the only code change is pointing the PostHog SDK to your proxy domain:

    posthog.init('phc_your_project_token', {
      api_host: 'https://e.yourdomain.com',
      ui_host: 'https://eu.posthog.com'  // or us.posthog.com
    })

    The api_host is your proxy. The ui_host points to PostHog's actual domain so features like the toolbar continue to work. That's it — everything else stays the same. Events flow through your proxy, and PostHog processes them as usual.

    Don't forget to update your Content Security Policy (CSP) headers if your application uses them. Replace the PostHog domains (eu.i.posthog.com, eu-assets.i.posthog.com) with your proxy domain in both script-src and connect-src directives.

    Open Source Templates

    The Terraform template that powers this deployment is open source. You can inspect every resource it creates, fork it, or run it directly without Staticbot:

    bitfiction/staticbot — cloudfront_reverse_proxy_template

    Contains main.tf, variables.tf, and a terraform.tfvars.template with all the configuration described in this article.

    All Staticbot infrastructure templates live in the same repository under infrastructure/_templates/. The proxy template sits alongside static website, subdomain, and top-domain templates. Each is self-contained Terraform that can be run standalone with tofu apply or managed through Staticbot's deployment pipeline.

    When You Don't Need This

    Not every team needs a self-hosted proxy. PostHog's managed reverse proxy is free for all Cloud users and takes about 5 minutes to set up. You just add a CNAME record and update your SDK. PostHog handles SSL, routing, and maintenance.

    The managed proxy is the right choice when:

    • You don't use Cloudflare Enterprise with zone holds
    • You don't need the proxy infrastructure in your own AWS account
    • DNS uncloaking resistance isn't a concern for your user base

    If any of those don't apply — or if you prefer owning the infrastructure — the CloudFront approach gives you full control.

    View the CloudFront Reverse Proxy template page for full details, features, and requirements

    Deploy Your PostHog Proxy in Minutes

    Connect your AWS account, pick your PostHog region and domain, and Staticbot handles the rest — pre-checks, Terraform, certificates, DNS. The template is open source and the infrastructure lives in your account.