# How to Deploy Open Notebook Behind a Reverse Proxy: Nginx, Traefik, and Caddy Guide

> Deploy Open Notebook behind Nginx Traefik or Caddy. Learn to configure your reverse proxy to route traffic efficiently to your Open Notebook deployment and its backend.

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

---

**Deploy Open Notebook behind a reverse proxy by forwarding all traffic to the Next.js frontend on port 8502, which internally routes `/api/*` requests to the FastAPI backend on port 5055, while setting the `API_URL` environment variable to your public HTTPS domain.**

Open Notebook (lfnovo/open-notebook) runs as a Dockerized application consisting of a Next.js frontend and a FastAPI backend. Since version 1.1, the frontend automatically handles internal API routing, enabling you to deploy Open Notebook behind a reverse proxy using a single external port without complex path-based routing configurations.

## Architecture Overview

Open Notebook's containerized design simplifies reverse proxy deployment by isolating the backend while exposing only the frontend.

### Container Roles and Default Ports

The application consists of two services that communicate internally:

- **Next.js frontend** (port `8502`): Serves the UI and proxies all `/api/*` requests to the backend
- **FastAPI backend** (port `5055`): Handles API endpoints but should never be directly exposed to browsers

According to the source code in [`docs/5-CONFIGURATION/reverse-proxy.md`](https://github.com/lfnovo/open-notebook/blob/main/docs/5-CONFIGURATION/reverse-proxy.md), the frontend includes a rewrite rule that proxies `/api/*` requests internally to `http://localhost:5055`. This eliminates the need for separate `/api/` routes in your proxy configuration and prevents CORS issues caused by mismatched origins.

## Nginx Reverse Proxy Configuration

For production deployments, Nginx provides robust TLS termination and fine-grained control over timeouts and upload limits.

### Full Production Configuration

Create an [`nginx.conf`](https://github.com/lfnovo/open-notebook/blob/main/nginx.conf) file that forwards all traffic to the Next.js container:

```nginx
events {
    worker_connections 1024;
}

http {
    upstream notebook {
        server open-notebook:8502;
    }

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

    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;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;

        client_max_body_size 100M;

        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

        location / {
            proxy_pass http://notebook;
            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;

            proxy_read_timeout 600s;
            proxy_connect_timeout 60s;
            proxy_send_timeout 600s;
        }
    }
}

```

### Critical Configuration Settings

When deploying Open Notebook behind Nginx, adjust these specific directives based on the implementation in `open_notebook/ai/…`:

- **`client_max_body_size 100M`**: Required for large file uploads (default 1 MiB is insufficient for document processing)
- **`proxy_read_timeout 600s`** and **`proxy_send_timeout 600s`**: Accommodate long-running AI operations such as transformations and podcast generation
- **Security headers**: Protect against clickjacking and MIME-type sniffing attacks

## Traefik Configuration

For Docker-native deployments, Traefik uses service labels for dynamic routing. Add these labels to your Open Notebook service in [`docker-compose.yml`](https://github.com/lfnovo/open-notebook/blob/main/docker-compose.yml):

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

```

Note that Traefik requires additional static configuration to set global timeouts for long-running operations, as documented in [`docs/5-CONFIGURATION/reverse-proxy.md`](https://github.com/lfnovo/open-notebook/blob/main/docs/5-CONFIGURATION/reverse-proxy.md).

## Caddy Configuration

Caddy handles HTTPS automatically with minimal configuration:

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

```

This configuration terminates TLS and forwards all traffic to the Next.js container while preserving the internal `/api/*` routing logic found in `frontend/src/lib/api/…`.

## Required Environment Variables

The `API_URL` variable is mandatory for reverse proxy deployments. According to the source code, the frontend uses this value to construct absolute API URLs in `open_notebook/ai/…`.

- **`API_URL`**: Set to your public HTTPS URL (e.g., `https://notebook.example.com`). If unset, the frontend attempts auto-detection, which fails behind complex proxies or when the internal container name differs from the public domain.
- **`INTERNAL_API_URL`** (optional): Use when running frontend and backend in separate containers to specify how the frontend reaches the API internally.

## Docker Compose Deployment

Deploy Open Notebook with your chosen reverse proxy using this structure:

```yaml
services:
  open-notebook:
    image: lfnovo/open_notebook:v1-latest
    environment:
      - API_URL=https://notebook.example.com
    ports:
      - "127.0.0.1:8502:8502"
    networks:
      - notebook-net

  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
    networks:
      - notebook-net

networks:
  notebook-net:
    driver: bridge

```

Binding port `8502` to `127.0.0.1` ensures the Next.js container is only accessible through the reverse proxy, not directly from external sources.

## Verification and Testing

After deployment, verify your reverse proxy configuration:

```bash

# Verify TLS termination

curl -I https://notebook.example.com

# Verify API routing through the proxy

curl https://notebook.example.com/api/config

# Check frontend loads correctly

curl -s https://notebook.example.com | head -n 20

```

A successful response from `/api/config` confirms that the frontend is correctly proxying API requests to the FastAPI backend via the internal routing mechanism.

## Summary

Deploying Open Notebook behind a reverse proxy requires understanding its single-port architecture:

- Configure your reverse proxy to forward **all** traffic to the Next.js container on port `8502`
- Set `API_URL` to your public HTTPS domain to ensure proper URL generation in the frontend
- Increase `client_max_body_size` to at least `100M` for file uploads
- Set `proxy_read_timeout` and `proxy_send_timeout` to `600s` for long-running AI operations
- Never expose port `5055` directly; the frontend handles internal API routing to the backend

## Frequently Asked Questions

### Do I need to expose the FastAPI backend port 5055 directly?

No. The Next.js frontend running on port `8502` includes an internal rewrite rule that proxies all `/api/*` requests to `http://localhost:5055`. Exposing port `5055` directly would bypass the frontend's routing and potentially expose your backend to security risks. The architecture is designed so only port `8502` requires external exposure.

### Why am I getting CORS errors when accessing the API behind a reverse proxy?

CORS errors typically occur when the `API_URL` environment variable is not set or mismatches your actual domain. The frontend constructs absolute URLs using this variable; if unset, it attempts auto-detection which often fails behind reverse proxies. Set `API_URL=https://your-domain.com` exactly as configured in your reverse proxy, including the `https://` prefix.

### How do I handle large file uploads through the reverse proxy?

Add `client_max_body_size 100M` to your Nginx server block, as the default 1 MiB limit is insufficient for Open Notebook's document upload features. For Traefik, use the appropriate middleware to increase body size limits. This setting must accommodate the maximum file size you intend to upload through the interface.

### Can I split the frontend and backend onto separate Docker hosts?

Yes, but you must set `INTERNAL_API_URL` to specify how the frontend reaches the backend internally. Normally, the frontend assumes the backend runs on `localhost:5055` inside the same container. When separated, update `INTERNAL_API_URL` to point to your backend service's internal address (e.g., `http://backend-service:5055`) while keeping `API_URL` set to the public-facing domain for browser requests.