Sign inSign up

hiteshjoshi/posthog_reverse_proxy

By hiteshjoshi

Updated about 1 year ago

Posthog reverse proxy to be deployed on you own docker infra.

Image
1

4.2K

hiteshjoshi/posthog_reverse_proxy repository overview

PostHog Nginx Reverse Proxy

This Docker container provides a secure nginx reverse proxy for PostHog analytics, allowing you to route analytics requests through your own domain to avoid ad blockers and maintain data privacy.

Features

Core Functionality
  • Domain-based access control: Only allows requests from your specified domain(s)
  • PostHog Cloud proxy: Routes requests to PostHog Cloud (US or EU regions)
  • Separate handling: Different routing for static assets and API calls
Improvements Over Standard Setup
  1. DNS Re-resolution: Forces nginx to re-resolve PostHog's DNS on each request, preventing issues with IP rotation
  2. SSL/TLS Fixes: Includes proxy_ssl_server_name to prevent SSL handshake failures
  3. Static Asset Caching: Caches static files (like recorder.js) for improved performance
  4. Health Check Endpoint: Built-in /health endpoint for monitoring
  5. Enhanced Logging: Detailed logging including cache status
  6. Redundant DNS Resolvers: Uses multiple DNS providers for reliability
  7. Connection Pooling: Maintains keepalive connections to PostHog servers

Quick Start

Using Docker
docker build -t posthog-proxy .
docker run -d \
  -p 8080:8080 \
  -e ALLOWED_DOMAIN=yourdomain.com \
  -e POSTHOG_CLOUD=us \
  posthog-proxy
Using Docker Compose
version: '3.8'
services:
  posthog-proxy:
    build: .
    ports:
      - "8080:8080"
    environment:
      - ALLOWED_DOMAIN=yourdomain.com
      - POSTHOG_CLOUD=us
      - CACHE_STATIC_DAYS=7
    restart: unless-stopped

Configuration

Environment Variables
VariableDefaultDescription
ALLOWED_DOMAINgoogle.comYour domain name (without protocol). Requests with referers from this domain and its subdomains will be allowed.
POSTHOG_CLOUDusPostHog cloud region. Use us for US cloud or eu for EU cloud.
CACHE_STATIC_DAYS7Number of days to cache static assets.
Client Configuration

Configure your PostHog client to use your proxy:

posthog.init('YOUR_API_KEY', {
    api_host: 'https://yourdomain.com',
    ui_host: 'https://app.posthog.com' // or 'https://eu.posthog.com' for EU
});

If you're serving the proxy on a subpath:

posthog.init('YOUR_API_KEY', {
    api_host: 'https://yourdomain.com/analytics',
});

Architecture

Request Flow
  1. Client makes request to https://yourdomain.com/*
  2. Nginx checks the Referer header:
    • Allows empty referer (direct access)
    • Allows localhost (for development)
    • Allows your configured domain and all subdomains
  3. For /static/* paths:
    • Proxies to https://[region]-assets.i.posthog.com/static/*
    • Caches responses for configured duration
    • Adds cache headers
  4. For all other paths:
    • Proxies to https://[region].i.posthog.com/*
    • No caching (real-time analytics data)
Security Features
  • Referer validation: Only accepts requests from your domain
  • No data storage: Proxy doesn't store any analytics data
  • SSL/TLS termination: Maintains secure connections to PostHog
  • No cookies: Doesn't set or forward cookies

Deployment Examples

Behind Traefik
services:
  posthog-proxy:
    build: .
    environment:
      - ALLOWED_DOMAIN=yourdomain.com
      - POSTHOG_CLOUD=us
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.posthog.rule=Host(`analytics.yourdomain.com`)"
      - "traefik.http.routers.posthog.tls=true"
      - "traefik.http.services.posthog.loadbalancer.server.port=8080"
On Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
  name: posthog-proxy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: posthog-proxy
  template:
    metadata:
      labels:
        app: posthog-proxy
    spec:
      containers:
      - name: nginx
        image: your-registry/posthog-proxy:latest
        ports:
        - containerPort: 8080
        env:
        - name: ALLOWED_DOMAIN
          value: "yourdomain.com"
        - name: POSTHOG_CLOUD
          value: "us"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10

Monitoring

Health Check

The proxy includes a health endpoint at /health that returns 200 OK when the service is running.

curl http://localhost:8080/health
# Returns: healthy
Logs

The proxy logs all requests with detailed information:

[01/Jan/2024:12:00:00 +0000] "GET /static/recorder.js HTTP/1.1" 200 "Referer: https://yourdomain.com" "Host: yourdomain.com" "Cache: HIT"
Cache Status

The X-Cache-Status header indicates cache performance for static assets:

  • HIT: Served from cache
  • MISS: Fetched from origin
  • UPDATING: Serving stale content while updating
  • STALE: Serving stale content due to origin error

Troubleshooting

SSL Handshake Failures

If you see SSL handshake errors in the logs, ensure:

  1. The proxy_ssl_server_name on; directive is present (already included)
  2. Your nginx version supports SNI (1.24+ does)
Recording Not Working

If events work but recordings don't:

  1. Check that /static/recorder.js requests are succeeding
  2. Verify the referer header is being sent by your application
  3. Check browser console for CORS errors
403 Forbidden Errors

This means the referer check is failing:

  1. Verify ALLOWED_DOMAIN matches your actual domain
  2. Check that your application sends the Referer header
  3. For development, requests from localhost are allowed
DNS Resolution Issues

The proxy is configured to handle PostHog's IP rotation automatically. If you still experience issues:

  1. Check that the DNS resolvers are accessible from your network
  2. The configuration uses multiple resolvers for redundancy
  3. DNS responses are cached for 5 minutes (configurable via valid=300s)

Contributing

To modify the proxy configuration:

  1. Edit entrypoint.sh for nginx configuration changes
  2. Update Dockerfile for build-time changes
  3. Test locally with: docker build -t test . && docker run -p 8080:8080 test
  4. Check nginx configuration validity inside container: docker exec <container> nginx -t

License

This configuration is provided as-is for use with PostHog services.

Tag summary

Content type

Image

Digest

sha256:8b61ea0d1

Size

6.9 MB

Last updated

about 1 year ago

docker pull hiteshjoshi/posthog_reverse_proxy