# How to Configure a Reverse Proxy (Nginx or Caddy) with WebSocket Support for TREK

> Learn to configure Nginx or Caddy as a reverse proxy for TREK with WebSocket support. Enable upgrades, set body limits, and configure environment variables for secure and efficient operation.

- Repository: [Maurice/TREK](https://github.com/mauriceboe/TREK)
- Tags: how-to-guide
- Published: 2026-07-04

---

**To run TREK behind a reverse proxy, you must enable WebSocket upgrades on the `/ws` endpoint, increase the body size limit to at least 500 MiB for backup restores, and set `TRUST_PROXY=1` and `FORCE_HTTPS=true` environment variables.**

TREK is a real-time collaboration application that relies on persistent WebSocket connections for live updates. When deploying behind a TLS-terminating reverse proxy, proper header forwarding and connection timeouts are essential for functionality. This guide covers the exact configuration requirements for Nginx and Caddy based on the official TREK source code and documentation.

## Why WebSocket Support Is Critical for TREK

TREK establishes persistent connections at the **`/ws`** endpoint to synchronize state between clients and the server. In [`server/src/websocket.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/websocket.ts), the application initializes the WebSocket server and expects the proxy to handle the protocol upgrade.

If the reverse proxy blocks or terminates the `Upgrade` header, real-time features fail silently. You must also configure extended timeouts because collaboration sessions can remain active for hours or days.

## Required Environment Variables

TREK reads specific environment variables to trust headers from your reverse proxy and enforce secure cookies. Configure these before starting the application:

- **`FORCE_HTTPS`**: Set to `true` to enable HTTP-to-HTTPS redirects and HSTS headers. This ensures the application recognizes secure connections even when TLS terminates at the proxy.
- **`TRUST_PROXY`**: Set to `1` (or higher if behind multiple proxies) to instruct Express to parse `X-Forwarded-For` headers and identify the real client IP.
- **`COOKIE_SECURE`**: Automatically enabled when `FORCE_HTTPS` is true or `NODE_ENV=production`, but can be set explicitly to enforce the `Secure` flag on the `trek_session` cookie.
- **`ALLOWED_ORIGINS`**: A comma-separated CORS whitelist (e.g., `https://trek.yourdomain.com`) to prevent cross-origin errors when the frontend connects via the proxy.

These variables are documented in [`wiki/Environment-Variables.md`](https://github.com/mauriceboe/TREK/blob/main/wiki/Environment-Variables.md) and consumed by the Express server configuration.

## Nginx Configuration

For Nginx, you must explicitly handle the WebSocket upgrade headers and increase body size limits. The following configuration implements both requirements while forwarding the necessary headers to TREK running on `localhost:3000`.

```nginx

# HTTP to HTTPS redirect

server {
    listen 80;
    server_name trek.yourdomain.com;
    return 301 https://$host$request_uri;
}

# TLS-enabled reverse proxy

server {
    listen 443 ssl http2;
    server_name trek.yourdomain.com;

    ssl_certificate /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    # WebSocket endpoint

    location /ws {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # Keep connection alive for 24 hours

        proxy_read_timeout 86400;
        
        # Support large backup restores

        client_max_body_size 500m;
    }

    # All other traffic

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        client_max_body_size 500m;
    }
}

```

### Handling the WebSocket Endpoint

The `/ws` location block in the configuration above is mandatory. The **`proxy_set_header Upgrade $http_upgrade`** and **`proxy_set_header Connection "upgrade"`** lines allow Nginx to forward the protocol upgrade request from the client to the TREK backend.

The **`proxy_read_timeout 86400`** directive (24 hours) prevents Nginx from closing idle WebSocket connections, which is crucial for long-running collaboration sessions.

### Supporting Large File Uploads

TREK's backup and restore functionality can upload archives exceeding 500 MiB. The **`client_max_body_size 500m`** directive overrides Nginx's default 1 MiB limit, preventing `413 Payload Too Large` errors during restore operations. This must be set in both the `/ws` location and the general `/` location to cover all upload paths.

## Caddy Configuration

Caddy handles WebSocket upgrades automatically, resulting in a cleaner configuration. However, you must still explicitly configure the body size limit for backup restores.

```caddy
trek.yourdomain.com {
    tls you@example.com
    
    # Allow large backup uploads

    request_body max_size 500mb
    
    # Proxy all traffic including WebSocket

    reverse_proxy localhost:3000
}

```

If you terminate TLS upstream (e.g., at a cloud load balancer), omit the `tls` directive. Caddy will still correctly proxy WebSocket traffic without additional `Upgrade` header configuration, unlike Nginx.

## Verifying Your Proxy Setup

After configuring your proxy, verify that headers are correctly forwarded by checking the TREK application logs. The server should report the client's real IP address rather than the proxy's internal IP.

During development, you can inspect the proxy configuration in [`client/vite.config.js`](https://github.com/mauriceboe/TREK/blob/main/client/vite.config.js), which demonstrates how the Vite dev server proxies `/ws` to the backend. This file serves as a reference for the expected header behavior.

## Summary

- **WebSocket endpoint**: The `/ws` path requires `Upgrade` and `Connection` header forwarding in Nginx; Caddy handles this automatically.
- **Body size limits**: Set `client_max_body_size 500m` (Nginx) or `request_body max_size 500mb` (Caddy) to support backup restores.
- **Environment variables**: Set `TRUST_PROXY=1` and `FORCE_HTTPS=true` so TREK correctly identifies secure connections and client IPs.
- **Timeouts**: Configure `proxy_read_timeout 86400` in Nginx to prevent WebSocket disconnections during idle periods.

## Frequently Asked Questions

### Does TREK require a specific reverse proxy?

No, TREK works with any reverse proxy that supports WebSocket upgrades and large request bodies. The repository provides official examples for Nginx and Caddy in [`wiki/Reverse-Proxy.md`](https://github.com/mauriceboe/TREK/blob/main/wiki/Reverse-Proxy.md), but HAProxy, Traefik, or cloud load balancers will work provided they forward the `X-Forwarded-Proto` and `X-Forwarded-For` headers.

### What is the maximum file size for backup restores?

The default configuration supports archives up to 500 MiB. You can adjust this limit by modifying the `client_max_body_size` (Nginx) or `request_body max_size` (Caddy) directive to match your storage capacity. Larger restores may also require increasing the `proxy_read_timeout` to prevent disconnections during slow uploads.

### Why does TREK need the X-Forwarded-Proto header?

TREK uses the `X-Forwarded-Proto` header to determine whether the original client connection used HTTPS. This is essential when `FORCE_HTTPS` is enabled, as the application must know to send secure cookies and redirect HTTP requests even though the connection between the proxy and TREK uses plain HTTP.

### Can I change the WebSocket endpoint path from /ws?

The `/ws` path is hardcoded in [`server/src/websocket.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/websocket.ts) and referenced in the client-side connection logic. Changing it would require modifying the source code and rebuilding the application. For standard deployments, keep the proxy configuration pointing to `/ws` as shown in the documentation.