Rybbit
Proxy Guide

Nginx Proxy Setup

Configure Nginx reverse proxy to serve Rybbit tracking and bypass ad blockers

Nginx is a powerful web server and reverse proxy that makes it easy to proxy Rybbit tracking through your own domain. This guide shows how to configure Nginx to forward tracking requests to Rybbit servers while caching static scripts for better performance.

Overview

Nginx's proxy_pass directive lets you forward requests from your domain to Rybbit's servers. Combined with caching, this provides excellent performance and reliability for proxying analytics.

What you'll achieve:

  • Proxy all Rybbit endpoints through your domain
  • Cache static scripts for better performance
  • Forward necessary headers for accurate tracking
  • Support all Rybbit features (session replay, Web Vitals, custom events)

Prerequisites

  • Nginx installed (version 1.18 or later recommended)
  • SSL/TLS certificate configured (Let's Encrypt recommended)
  • Your Rybbit instance URL:
    • Cloud hosted: https://app.rybbit.io
    • Self-hosted: Your instance URL
  • Your Rybbit site ID (found in your dashboard)

Implementation

Configure Nginx Proxy

Add a new location block (or update existing configuration) in your Nginx site configuration:

Minimal configuration for basic tracking:

# /etc/nginx/sites-available/yourdomain.com
server {
    listen 443 ssl http2;
    server_name yourdomain.com;

    # SSL configuration
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    # Main tracking script
    location = /analytics/script.js {
        proxy_pass https://app.rybbit.io/api/script.js;
        proxy_set_header Host app.rybbit.io;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_ssl_server_name on;

        proxy_cache_valid 200 1h;
    }

    # Event tracking
    location = /analytics/track {
        proxy_pass https://app.rybbit.io/api/track;
        proxy_set_header Host app.rybbit.io;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_ssl_server_name on;
    }
}

For better performance with caching, define a cache zone:

# /etc/nginx/nginx.conf (http block)
http {
    # Define cache zone for Rybbit
    proxy_cache_path /var/cache/nginx/rybbit
        levels=1:2
        keys_zone=rybbit_cache:10m
        max_size=100m
        inactive=60m
        use_temp_path=off;

    # ... rest of http config
}

Then in your site config:

# /etc/nginx/sites-available/yourdomain.com
server {
    # ... server config

    location = /analytics/script.js {
        proxy_pass https://app.rybbit.io/api/script.js;
        proxy_set_header Host app.rybbit.io;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_ssl_server_name on;

        # Use the cache zone
        proxy_cache rybbit_cache;
        proxy_cache_valid 200 1h;
        proxy_cache_key "$scheme$request_method$host$request_uri";
        add_header X-Cache-Status $upstream_cache_status;
    }

    # ... other locations
}

Important: The proxy_set_header X-Real-IP and X-Forwarded-For headers are critical for accurate geolocation and user identification. Without these, all traffic will appear to come from your Nginx server's IP.

Create Cache Directory (Optional)

If using a cache zone, create the cache directory:

sudo mkdir -p /var/cache/nginx/rybbit
sudo chown www-data:www-data /var/cache/nginx/rybbit

Test Nginx Configuration

Before reloading Nginx, test the configuration for syntax errors:

sudo nginx -t

You should see:

nginx: configuration file /etc/nginx/nginx.conf test is successful

Reload Nginx

Apply the changes by reloading Nginx:

sudo systemctl reload nginx

Or if you prefer:

sudo nginx -s reload

Update Your Tracking Script

Update your HTML to load the script from your proxied domain:

<!DOCTYPE html>
<html>
<head>
    <!-- ... other head elements -->
    <script src="/analytics/script.js" async data-site-id="YOUR_SITE_ID"></script>
</head>
<body>
    <!-- Your content -->
</body>
</html>

Replace YOUR_SITE_ID with your actual site ID from the Rybbit dashboard.

Verify the Setup

Test your configuration:

  1. Check Nginx is running:

    sudo systemctl status nginx
  2. Test script loading:

    curl -I https://yourdomain.com/analytics/script.js

    You should see:

    HTTP/2 200
    content-type: application/javascript
    x-cache-status: MISS  # First request
  3. Test again to verify caching:

    curl -I https://yourdomain.com/analytics/script.js

    You should see:

    HTTP/2 200
    x-cache-status: HIT  # Cached!
  4. Open your website in a browser with Developer Tools and verify:

    • Script loads from /analytics/script.js (your domain)
    • Tracking requests go to /analytics/track (your domain)
    • Data appears in your Rybbit dashboard after 1-2 minutes

How It Works

Nginx's proxy_pass directive transparently forwards requests to Rybbit's servers:

  1. Browser requests https://yourdomain.com/analytics/script.js
  2. Nginx matches the location block and forwards to https://app.rybbit.io/api/script.js
  3. Nginx sets necessary headers (X-Real-IP, X-Forwarded-For) for accurate tracking
  4. Response is cached (if configured) and sent back to browser
  5. All subsequent tracking requests follow the same pattern

The Rybbit script auto-detects it's being served from your domain and sends all tracking data to your domain's /analytics/* endpoints.

Performance Optimization

Caching Strategy

Configure different cache durations based on content type:

# Scripts - cache for 1 hour
location ~ ^/analytics/(script|replay|metrics)\.js$ {
    proxy_pass https://app.rybbit.io/api/$1.js;
    # ... proxy headers
    proxy_cache_valid 200 1h;
    proxy_cache_valid 404 1m;  # Cache 404s briefly
}

# Config - cache for 5 minutes (changes when you update dashboard settings)
location ~ ^/analytics/site/tracking-config/(.*)$ {
    proxy_pass https://app.rybbit.io/api/site/tracking-config/$1;
    # ... proxy headers
    proxy_cache_valid 200 5m;
}

# Tracking - never cache (each request is unique)
location ~ ^/analytics/(track|identify)$ {
    proxy_pass https://app.rybbit.io/api/$1;
    # ... proxy headers
    # No caching directives
}

Gzip Compression

Enable compression for JavaScript files:

# In http or server block
gzip on;
gzip_vary on;
gzip_types application/javascript text/javascript;
gzip_min_length 1000;

Connection Pooling

Keep connections to Rybbit backend alive for better performance:

upstream rybbit_backend {
    server app.rybbit.io:443;
    keepalive 32;
}

location /analytics/ {
    proxy_pass https://rybbit_backend/api/;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    # ... other proxy headers
}

Proxy Buffering

For better performance with larger session replay uploads:

location ~ ^/analytics/session-replay/record/ {
    proxy_pass https://app.rybbit.io/api/session-replay/record/;
    # ... proxy headers

    proxy_buffering on;
    proxy_buffer_size 4k;
    proxy_buffers 8 4k;
    proxy_busy_buffers_size 8k;
    client_max_body_size 10M;
}

Security Considerations

Rate Limiting

Protect your proxy from abuse with rate limiting:

# In http block
http {
    limit_req_zone $binary_remote_addr zone=analytics_limit:10m rate=10r/s;

    # ... rest of config
}

# In server block
location = /analytics/track {
    limit_req zone=analytics_limit burst=20 nodelay;
    proxy_pass https://app.rybbit.io/api/track;
    # ... proxy headers
}

This limits to 10 requests per second per IP, with bursts up to 20.

Request Size Limits

Set appropriate limits for different endpoints:

# Default for most endpoints
client_max_body_size 1M;

# Larger limit for session replay
location ~ ^/analytics/session-replay/record/ {
    client_max_body_size 10M;
    # ... proxy config
}

Security Headers

Add security headers to your responses:

add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header Referrer-Policy strict-origin-when-cross-origin;

Troubleshooting

502 Bad Gateway

Problem: Nginx returns 502 error when accessing analytics endpoints.

Solution:

  1. Check Rybbit backend is accessible:
    curl -I https://app.rybbit.io/api/script.js
  2. Verify proxy_ssl_server_name on is set
  3. Check Nginx error logs:
    sudo tail -f /var/log/nginx/error.log

Cache not working

Problem: X-Cache-Status always shows MISS.

Solution:

  1. Verify cache directory exists and is writable
  2. Check proxy_cache_path is defined in http block
  3. Ensure proxy_cache directive uses correct zone name
  4. Check cache key is consistent:
    proxy_cache_key "$scheme$request_method$host$request_uri";

Incorrect geolocation in Rybbit

Problem: All visitors show same location (your server's location).

Solution: Ensure you're forwarding client IP headers:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

SSL errors in Nginx logs

Problem: Logs show SSL verification errors when connecting to Rybbit.

Solution: Add proxy_ssl_server_name on to enable SNI:

location /analytics/ {
    proxy_pass https://app.rybbit.io/api/;
    proxy_ssl_server_name on;  # Enable SNI
    # ... other config
}

Advanced Configuration

Subdomain Proxy

Use a dedicated subdomain for analytics:

# /etc/nginx/sites-available/analytics.yourdomain.com
server {
    listen 443 ssl http2;
    server_name analytics.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/analytics.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/analytics.yourdomain.com/privkey.pem;

    # Proxy all requests to Rybbit
    location / {
        proxy_pass https://app.rybbit.io/api/;
        proxy_set_header Host app.rybbit.io;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_ssl_server_name on;
    }
}

Then use:

<script src="https://analytics.yourdomain.com/script.js" data-site-id="123"></script>

Multiple Rybbit Instances

If you need to proxy multiple Rybbit instances:

location /analytics-prod/ {
    proxy_pass https://prod.rybbit.io/api/;
    # ... proxy config
}

location /analytics-staging/ {
    proxy_pass https://staging.rybbit.io/api/;
    # ... proxy config
}