Skip to main content

Why Use a Reverse Proxy?

While technically not required, using a reverse proxy is highly recommended for production deployments:
  • HTTPS support: Secure communication with SSL/TLS certificates
  • Port management: Serve multiple applications on standard ports (80/443)
  • Performance: Static file caching and compression
  • Security: Additional layer of protection and access control
Running OTT without HTTPS is not supported. Always use a reverse proxy with SSL/TLS in production.

Proxy Requirements

Your reverse proxy must handle:
  • WebSocket upgrades: Required for real-time room synchronization
  • All requests for index.html: Proper SPA routing
  • Headers:
    • Forward Set-Cookie header in responses
    • Forward Authorization header in requests
    • Set X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host

Nginx Configuration

Here’s a complete nginx configuration for OTT:
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    listen 443 ssl http2;
    server_name example.com;

    # SSL configuration (generated by certbot)
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        
        # WebSocket support
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # Forward headers
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        
        # Don't cache upgraded connections
        proxy_cache_bypass $http_upgrade;
        
        # Pass cookies
        proxy_pass_header Set-Cookie;

        # Optional: Prevent frequent disconnects
        proxy_connect_timeout 7d;
        proxy_read_timeout 7d;
        proxy_send_timeout 7d;
        proxy_socket_keepalive on;
    }
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name example.com;
    return 301 https://$server_name$request_uri;
}

Configuration Breakdown

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}
This creates a mapping to properly handle WebSocket upgrade requests. When the Upgrade header is present, it upgrades the connection; otherwise, it closes it.
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
Replace with your SSL certificate paths. Use Certbot to obtain free Let’s Encrypt certificates.
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
These headers preserve the original request information when proxying to OTT. Important for:
  • Correct URL generation
  • Rate limiting based on client IP
  • Security features
proxy_connect_timeout 7d;
proxy_read_timeout 7d;
proxy_send_timeout 7d;
proxy_socket_keepalive on;
These extended timeouts prevent WebSocket connections from being dropped. Use these settings if you experience frequent client disconnects and reconnects.

Trust Proxy Configuration

When using a reverse proxy, configure OTT to trust the proxy layer(s):
trust_proxy = 1
Set this to the number of proxy layers between the client and OTT:
  • 1 proxy layer: nginx → OTT
  • 2 proxy layers: Cloudflare → nginx → OTT
  • 3 proxy layers: Cloudflare → load balancer → nginx → OTT
Setting trust_proxy incorrectly can lead to security issues or broken functionality. Count your proxy layers carefully.

Multiple Proxy Layers

If you have multiple reverse proxies (e.g., Cloudflare in front of nginx), ensure each layer forwards the headers correctly:
# If behind Cloudflare or another CDN
set_real_ip_from 0.0.0.0/0;  # Or specific Cloudflare IP ranges
real_ip_header CF-Connecting-IP;  # For Cloudflare
# real_ip_header X-Forwarded-For;  # For other proxies
Then set trust_proxy = 2 (or higher) in your OTT configuration.

Caddy Configuration

If you prefer Caddy, here’s an equivalent configuration:
example.com {
    reverse_proxy localhost:3000 {
        # Headers are automatically forwarded
        transport http {
            keepalive 7d
            keepalive_idle_conns 100
        }
    }
}
Caddy automatically handles:
  • HTTPS with automatic certificate management
  • WebSocket upgrades
  • Proper header forwarding

Apache Configuration

For Apache with mod_proxy:
<VirtualHost *:443>
    ServerName example.com
    
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    
    ProxyPreserveHost On
    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/
    
    # WebSocket support
    RewriteEngine on
    RewriteCond %{HTTP:Upgrade} websocket [NC]
    RewriteCond %{HTTP:Connection} upgrade [NC]
    RewriteRule ^/?(.*) "ws://localhost:3000/$1" [P,L]
    
    # Forward headers
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Port "443"
</VirtualHost>
Enable required modules:
a2enmod proxy proxy_http proxy_wstunnel rewrite ssl headers
systemctl restart apache2

Traefik Configuration

For Traefik (v2+) with Docker:
services:
  opentogethertube:
    image: dyc3/opentogethertube:latest
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.ott.rule=Host(`example.com`)"
      - "traefik.http.routers.ott.entrypoints=websecure"
      - "traefik.http.routers.ott.tls.certresolver=letsencrypt"
      - "traefik.http.services.ott.loadbalancer.server.port=8080"

SSL Certificate Management

Let’s Encrypt with Certbot

Obtain free SSL certificates:
1

Install Certbot

# Ubuntu/Debian
sudo apt install certbot python3-certbot-nginx

# CentOS/RHEL
sudo yum install certbot python3-certbot-nginx
2

Obtain certificate

sudo certbot --nginx -d example.com
Certbot will automatically configure nginx for HTTPS.
3

Enable auto-renewal

sudo certbot renew --dry-run
Certbot automatically sets up renewal via systemd timer or cron.

Testing Your Configuration

1

Test nginx configuration

sudo nginx -t
2

Reload nginx

sudo systemctl reload nginx
3

Verify HTTPS

Visit https://example.com and verify:
  • Page loads correctly
  • No certificate warnings
  • WebSocket connection succeeds (check browser console)
4

Test SSL configuration

Use SSL Labs to verify your SSL configuration.

Troubleshooting

WebSocket connection fails

  • Verify the Upgrade and Connection headers are forwarded
  • Check that proxy_http_version 1.1 is set
  • Ensure firewall allows WebSocket connections

Incorrect client IP addresses

  • Verify X-Forwarded-For header is set correctly
  • Adjust trust_proxy setting to match your proxy layers
  • Check nginx set_real_ip_from configuration

Session/authentication issues

  • Ensure Set-Cookie header is forwarded
  • Verify proxy_pass_header Set-Cookie is set
  • Check that force_insecure_cookies is configured correctly

Frequent disconnects

  • Increase proxy timeout values
  • Enable proxy_socket_keepalive
  • Check for firewall connection timeout settings

Build docs developers (and LLMs) love