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

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, 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 file that forwards all traffic to the Next.js container:

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:

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.

Caddy Configuration

Caddy handles HTTPS automatically with minimal configuration:

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:

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:


# 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →