# How to Configure a Reverse Proxy for Production with Open Notebook

> Learn how to configure a reverse proxy for Open Notebook in production. Expose port 8502 and set API_URL to your public domain for secure traffic routing.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-06-05

---

**Expose only port 8502 through your TLS-terminating reverse proxy and set the `API_URL` environment variable to your public domain so Open Notebook correctly routes frontend and API traffic in production.**

Open Notebook is a three-tier open-source application that requires careful proxy configuration before facing the public internet. Since version 1.1, the Next.js frontend automatically forwards `/api/*` requests to the FastAPI backend, which means you can configure a reverse proxy for production using a single upstream port. This guide walks through the exact responsibilities, headers, timeouts, and working examples derived from the `lfnovo/open-notebook` source code.

## Architecture and Port Requirements

Open Notebook runs three services internally: a **Next.js frontend** on port `8502`, a **FastAPI backend** on port `5055`, and **SurrealDB** on port `8000`. According to the `lfnovo/open-notebook` source code, the frontend—configured in [`frontend/next.config.ts`](https://github.com/lfnovo/open-notebook/blob/main/frontend/next.config.ts)—rewrites any request under `/api/*` to the backend service automatically. Because of this internal routing, a production reverse proxy only needs to expose port `8502` publicly; traffic to `/api/*` is proxied internally from the frontend container to the FastAPI entry point in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py).

## Reverse Proxy Responsibilities

A production reverse proxy sitting in front of Open Notebook should handle four specific jobs:

- **Terminate TLS** — Provide HTTPS for the public domain and offload encryption from the application containers.
- **Forward traffic** — Send all requests to `http://open-notebook:8502` (or the equivalent container hostname and port).
- **Handle time-outs and large uploads** — Set generous `proxy_*_timeout` and `client_max_body_size` values because operations like podcast generation can run for several minutes.
- **Set proper headers** — Forward `Host`, `X-Forwarded-Proto`, `X-Real-IP`, and related headers so the frontend can correctly auto-detect the public URL or use the explicitly set `API_URL` environment variable.

## Production Configuration Examples

### Nginx (Recommended)

The documentation in [`docs/5-CONFIGURATION/reverse-proxy.md`](https://github.com/lfnovo/open-notebook/blob/main/docs/5-CONFIGURATION/reverse-proxy.md) provides a complete Nginx example that terminates TLS and forwards traffic to the Next.js frontend.

```nginx

# /etc/nginx/nginx.conf (or a site-specific file)

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

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

    # Allow large file uploads (up to 100 MiB)

    client_max_body_size 100M;

    location / {
        proxy_pass http://open-notebook:8502;
        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;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_cache_bypass $http_upgrade;

        # Long-running operations timeout (600 s)

        proxy_read_timeout 600s;
        proxy_send_timeout 600s;
    }
}

# HTTP -> HTTPS redirect

server {
    listen 80;
    server_name notebook.example.com;
    return 301 https://$server_name$request_uri;
}

```

### Caddy (Automatic HTTPS)

Caddy handles certificate management automatically. The following Caddyfile targets port `8502` and extends read and write timeouts to accommodate long-running Open Notebook tasks.

```caddy
notebook.example.com {
    reverse_proxy open-notebook:8502 {
        transport http {
            read_timeout 600s
            write_timeout 600s
        }
    }
}

```

### Traefik (Docker-Compose Integration)

If you orchestrate containers with Docker Compose, Traefik labels can route public HTTPS traffic directly to the frontend without exposing additional host ports.

```yaml
services:
  open-notebook:
    image: lfnovo/open_notebook:v1-latest
    environment:
      - API_URL=https://notebook.example.com
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.notebook.rule=Host(`notebook.example.com`)"
      - "traefik.http.routers.notebook.entrypoints=websecure"
      - "traefik.http.routers.notebook.tls.certresolver=myresolver"
      - "traefik.http.services.notebook.loadbalancer.server.port=8502"
      - "traefik.http.services.notebook.loadbalancer.responseforwarding.flushinterval=100ms"

```

### Docker Compose (Single-Service Setup)

For co-located deployments, bind the Open Notebook container to localhost and place Nginx on the public edge.

```yaml
services:
  open-notebook:
    image: lfnovo/open_notebook:v1-latest
    environment:
      - API_URL=https://notebook.example.com
    ports:
      - "127.0.0.1:8502:8502"   # Only expose to the reverse proxy

    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/nginx/ssl:ro
    depends_on:
      - open-notebook
    restart: unless-stopped

```

## Critical Environment Variables

### API_URL

Set `API_URL` to the full public URL including the scheme, for example `https://notebook.example.com`. The Open Notebook frontend uses this value to build correct absolute API calls. Do **not** append `/api` to this variable because the system adds the path automatically when rewriting requests to the backend.

## Summary

- Open Notebook exposes a **single public port** (`8502`) in production because the Next.js frontend in [`frontend/next.config.ts`](https://github.com/lfnovo/open-notebook/blob/main/frontend/next.config.ts) internally proxies `/api/*` traffic to the FastAPI backend.
- Configure a reverse proxy for production by terminating TLS, setting generous time-outs, allowing large upload bodies, and forwarding `X-Forwarded-*` headers.
- Always define **`API_URL`** as the public domain without `/api` so the frontend generates valid absolute URLs.
- Use **Nginx**, **Caddy**, or **Traefik** examples from [`docs/5-CONFIGURATION/reverse-proxy.md`](https://github.com/lfnovo/open-notebook/blob/main/docs/5-CONFIGURATION/reverse-proxy.md) depending on your infrastructure preferences.

## Frequently Asked Questions

### Do I need to expose port 5055 or 8000 to the internet?

You should leave both the FastAPI backend on port `5055` and SurrealDB on port `8000` unexposed to the public internet. Since version 1.1, the Next.js frontend automatically proxies `/api/*` requests to the backend internally, which means your reverse proxy only needs to forward traffic to port `8502`. Exposing the other ports directly introduces unnecessary security risk.

### What happens if I do not set the API_URL environment variable?

The frontend relies on `API_URL` to build correct absolute API calls for public links and external resources. Without it, the application may generate broken URLs that point to internal hostnames instead of your public domain. Set it to the full scheme and domain, such as `https://notebook.example.com`, and do not append `/api` because the frontend rewrite logic handles that path automatically.

### How do I handle long-running requests like podcast generation?

Operations like podcast generation can take several minutes, so your reverse proxy must tolerate slow responses. In Nginx, set `proxy_read_timeout 600s` and `proxy_send_timeout 600s`; in Caddy, configure `read_timeout 600s` and `write_timeout 600s` in the transport block. These values prevent the proxy from closing the connection before the FastAPI backend in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) finishes processing.

### Can I route `/api/*` directly to the backend instead of through the frontend?

This is only necessary if you want to expose the API directly for external integrations bypassing the frontend. In that advanced setup, route `/api/*` to port `5055` while sending all other traffic to port `8502`. For standard deployments, proxying everything through port `8502` is simpler and fully supported by the rewrite rules in [`frontend/next.config.ts`](https://github.com/lfnovo/open-notebook/blob/main/frontend/next.config.ts).