# How to Configure Nginx as a Reverse Proxy for TREK

> Learn to configure Nginx as a reverse proxy for TREK. Terminate TLS, forward traffic, proxy WebSocket upgrades, and set X-Forwarded-Proto headers for secure HTTPS handling. Optimize your TREK setup today.

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

---

**Configure Nginx to terminate TLS, forward traffic to TREK's Node.js server on port 3000, and proxy WebSocket upgrades at `/ws` while setting `X-Forwarded-Proto` headers so TREK correctly handles HTTPS redirects and URL generation.**

TREK is a self-hosted travel planner that exposes a Node.js application on port 3000. To deploy it securely in production, you must configure Nginx as a reverse proxy for TREK to handle TLS termination, client IP preservation, and WebSocket connections for real-time collaboration features.

## Prerequisites for Nginx Reverse Proxy Configuration

Before editing your Nginx configuration, ensure you have:

- A running TREK instance accessible on `localhost:3000` (the default Docker Compose exposes this port)
- SSL certificates for your domain (e.g., from Let's Encrypt at `/etc/ssl/fullchain.pem` and `/etc/ssl/privkey.pem`)
- Nginx installed on the host or in a container with network access to the TREK service

## Complete Nginx Configuration for TREK

The official configuration documented in the repository's [`README.md`](https://github.com/mauriceboe/TREK/blob/main/README.md) splits traffic into two server blocks: one for HTTP redirection and one for HTTPS termination.

### HTTP to HTTPS Redirect

Force all cleartext traffic to the secure endpoint to ensure session cookies and travel data remain encrypted:

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

```

### TLS Termination and Upstream Proxy

The HTTPS server block handles TLS certificates, upload size limits, and proxy headers required by TREK's middleware:

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

    ssl_certificate     /etc/ssl/fullchain.pem;
    ssl_certificate_key /etc/ssl/privkey.pem;

    # 500 MB covers backup-restore uploads (capped at 500 MB server-side)

    client_max_body_size 500m;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        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;
    }
}

```

The `X-Forwarded-Proto` header is critical because TREK's [`globalMiddleware.ts`](https://github.com/mauriceboe/TREK/blob/main/globalMiddleware.ts) (lines 27-30) reads this to determine the original request protocol, enabling the optional `FORCE_HTTPS` redirect logic and correct absolute URL generation.

### WebSocket Support for Real-Time Collaboration

TREK uses WebSockets for live collaboration on the `/ws` endpoint. Nginx must forward the `Upgrade` and `Connection` headers and disable the default 60-second read timeout:

```nginx
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_read_timeout 86400;
}

```

Without this block, the collaborative editing features will fail to connect because the proxy will treat the WebSocket handshake as a standard HTTP request.

## Configuring TREK to Trust the Proxy

TREK must explicitly trust the Nginx reverse proxy to interpret `X-Forwarded-*` headers correctly. Set the `TRUST_PROXY` environment variable in your Docker Compose configuration:

```yaml
services:
  app:
    image: mauriceboe/trek:latest
    environment:
      - NODE_ENV=production
      - PORT=3000
      - TRUST_PROXY=1  # Tell TREK there is one trusted proxy (Nginx)

      # - FORCE_HTTPS=true  # Optional: let TREK handle redirects (Nginx recommended instead)

```

In [`server/src/middleware/globalMiddleware.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/middleware/globalMiddleware.ts), the application reads `TRUST_PROXY` and executes `app.set('trust proxy', process.env.TRUST_PROXY || 1)`. This enables `req.secure` and `req.protocol` to reflect the original client scheme forwarded by Nginx, ensuring secure cookie settings and correct URL generation in [`server/src/services/cookie.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/cookie.ts) and [`server/src/services/shareService.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/services/shareService.ts).

## Docker Compose Deployment Example

Place the following [`docker-compose.yml`](https://github.com/mauriceboe/TREK/blob/main/docker-compose.yml) alongside your Nginx configuration to ensure TREK binds to the expected port and respects the reverse proxy headers:

```yaml
version: '3.8'
services:
  app:
    image: mauriceboe/trek:latest
    container_name: trek
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - PORT=3000
      - ENCRYPTION_KEY=${ENCRYPTION_KEY}
      - TRUST_PROXY=1
    volumes:
      - ./data:/app/data
      - ./uploads:/app/uploads
    restart: unless-stopped

```

Ensure your Nginx `proxy_pass` points to `http://localhost:3000` (or the container's IP if Nginx runs in Docker) and that the `TRUST_PROXY` value matches the number of proxy layers (typically `1` for a single Nginx instance).

## Testing Your Reverse Proxy Setup

Verify the configuration works end-to-end:

1. **Test HTTP to HTTPS redirect:**

```bash
curl -I http://trek.yourdomain.com

```

You should see `Location: https://trek.yourdomain.com/`.

2. **Test WebSocket connectivity:**

```bash
wscat -c ws://trek.yourdomain.com/ws

```

The connection should open without error if the `/ws` location block is configured correctly.

3. **Verify TREK recognizes HTTPS:**

Check the browser network tab or server logs to confirm that `req.secure` returns `true` when accessing via HTTPS, indicating the `X-Forwarded-Proto` header is being honored.

## Summary

- **Terminate TLS at Nginx** using `listen 443 ssl http2` and forward to port 3000, offloading cryptography from the Node.js process.
- **Preserve proxy headers** including `X-Forwarded-Proto` so TREK's [`globalMiddleware.ts`](https://github.com/mauriceboe/TREK/blob/main/globalMiddleware.ts) can correctly identify secure connections and generate absolute URLs.
- **Enable WebSocket support** by adding a specific `/ws` location block with `Upgrade` and `Connection` headers, plus an extended `proxy_read_timeout`.
- **Set `TRUST_PROXY=1`** in your Docker Compose environment to align with the trust proxy logic in [`server/src/middleware/globalMiddleware.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/middleware/globalMiddleware.ts).
- **Allow large uploads** by setting `client_max_body_size 500m` to accommodate TREK's 500 MB backup restore functionality.

## Frequently Asked Questions

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

TREK relies on the `X-Forwarded-Proto` header to determine the original request scheme when running behind a reverse proxy. According to [`server/src/middleware/globalMiddleware.ts`](https://github.com/mauriceboe/TREK/blob/main/server/src/middleware/globalMiddleware.ts), the application sets `trust proxy` based on the `TRUST_PROXY` environment variable, allowing `req.secure` and `req.protocol` to reflect the client's original connection rather than the internal HTTP proxy link. This enables the optional `FORCE_HTTPS` redirect and ensures secure cookie attributes are set correctly.

### What happens if I don't configure the `/ws` location block in Nginx?

Without the specific `/ws` configuration, Nginx will treat WebSocket upgrade requests as standard HTTP traffic, causing the connection to fail after the 60-second default timeout. TREK's real-time collaboration features require persistent WebSocket connections to the `/ws` endpoint, so you must forward the `Upgrade` and `Connection` headers and set `proxy_read_timeout` to a high value (such as 86400 seconds) to prevent timeouts during idle periods.

### How does `client_max_body_size` affect TREK functionality?

TREK allows users to upload trip backups up to 500 MB. If Nginx's default `client_max_body_size` (1 MB) is not increased, the reverse proxy will return a 413 Request Entity Too Large error before the request reaches TREK. Setting `client_max_body_size 500m` in the Nginx server block ensures large file uploads reach the application server successfully.

### Can I run Nginx in a Docker container alongside TREK?

Yes, you can run Nginx in a separate container or use a reverse proxy network. Ensure that Nginx can reach the TREK container via the internal Docker network (e.g., `http://trek:3000` instead of `localhost:3000`) and that the `TRUST_PROXY` count accounts for any additional proxy layers. If Nginx is the only reverse proxy, setting `TRUST_PROXY=1` remains correct regardless of whether Nginx runs on the host or in a container.