How to Set Up Open Notebook Behind a Reverse Proxy (NGINX or Traefik)

Open Notebook requires a reverse proxy to securely expose its Next.js frontend (port 3000) and FastAPI backend (port 5055) through a single HTTPS endpoint while keeping internal services isolated on the Docker network.

Open Notebook is a three-tier open-source application that bundles a Next.js UI, FastAPI service, and SurrealDB database. To deploy it securely in production, you must set up Open Notebook behind a reverse proxy such as NGINX or Traefik that handles TLS termination and path-based routing. This guide references the official configuration documented in docs/5-CONFIGURATION/reverse-proxy.md and provides runnable configurations for both proxy options.

Architecture Overview

Open Notebook runs as three distinct services:

  • Frontend: A Next.js application served internally on port 3000.
  • API: A FastAPI service on port 5055 that manages notebook logic, source documents, and chat interactions.
  • Database: SurrealDB on port 8000 for persistent graph storage and vector embeddings.

The FastAPI backend in api/main.py exposes HTTP endpoints and health checks at /healthz, while the frontend in frontend/src/pages/_app.tsx expects an API URL defined at build time. In production, neither service should be directly exposed to the internet; instead, a reverse proxy handles all external traffic and forwards requests based on path prefixes.

Step 1: Isolate Services on the Docker Network

Before adding a reverse proxy, secure the internal services by removing public port bindings in your docker-compose.yml. Edit the file referenced in docs/1-INSTALLATION/docker-compose.md to ensure the frontend and api services are only accessible within the Docker network:

services:
  api:
    # Remove or comment out: ports: ["5055:5055"]

    expose:
      - "5055"
    
  frontend:
    # Remove or comment out: ports: ["3000:3000"]

    expose:
      - "3000"
    
  surrealdb:
    # Keep isolated on the internal network

    expose:
      - "8000"

Binding ports to 127.0.0.1:5055:5055 is also acceptable if the proxy runs on the host machine, but exposing them to 0.0.0.0 creates a security risk.

Step 2: Configure NGINX as a Reverse Proxy

NGINX terminates TLS and routes traffic based on URL paths. Create a configuration file that proxies all /api/* requests to the FastAPI service and all other traffic to the Next.js frontend.

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

    # TLS certificate paths (replace with your own or use Let's Encrypt)

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

    # Frontend (Next.js) – all non-API requests

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

    # API – path-based routing to FastAPI

    location /api/ {
        proxy_pass http://api:5055;
        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;
    }

    # Health check endpoint for container orchestration

    location /healthz {
        return 200 'OK';
        add_header Content-Type text/plain;
    }
}

Mount this configuration into an NGINX container or place it in /etc/nginx/conf.d/ if running NGINX on the host. The proxy_set_header directives ensure the FastAPI service in api/main.py receives the correct client IP and protocol information for CORS validation.

Step 3: Configure Traefik as a Reverse Proxy

Traefik discovers services automatically via Docker labels and handles TLS with Let's Encrypt automatically. Add a traefik service to your docker-compose.yml and label the existing services:

services:
  api:
    image: open-notebook-api
    expose:
      - "5055"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api.rule=PathPrefix(`/api`)"
      - "traefik.http.routers.api.entrypoints=websecure"
      - "traefik.http.routers.api.tls.certresolver=myresolver"
      - "traefik.http.services.api.loadbalancer.server.port=5055"

  frontend:
    image: open-notebook-frontend
    expose:
      - "3000"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.frontend.rule=PathPrefix(`/`)"
      - "traefik.http.routers.frontend.entrypoints=websecure"
      - "traefik.http.routers.frontend.tls.certresolver=myresolver"
      - "traefik.http.services.frontend.loadbalancer.server.port=3000"

  traefik:
    image: traefik:v2.11
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.myresolver.acme.tlschallenge=true"
      - "--certificatesresolvers.myresolver.acme.email=you@example.com"
      - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"  # Traefik dashboard

    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./letsencrypt:/letsencrypt"

Traefik routes requests matching /api/* to the FastAPI container on port 5055 and all other traffic to the Next.js frontend on port 3000. The myresolver certificate resolver automatically provisions and renews TLS certificates from Let's Encrypt.

Step 4: Update the Frontend Base URL

The Next.js frontend reads the API endpoint from frontend/.env.local. When running behind a reverse proxy, you must update this variable to point to the public HTTPS endpoint rather than the internal Docker service name.

Create or edit frontend/.env.local:


# .env.local

NEXT_PUBLIC_API_URL=https://notebook.example.com/api

As shown in frontend/.env.local.example, this variable is consumed by the application entry point in frontend/src/pages/_app.tsx to construct API requests. Rebuild the frontend container after changing this value so the Next.js build process embeds the correct URL.

Summary

Setting up Open Notebook behind a reverse proxy requires four key steps:

  • Isolate the Docker network by removing port bindings from the frontend and api services in docker-compose.yml to prevent direct external access.
  • Configure path-based routing so that /api/* requests reach the FastAPI service on port 5055 and all other traffic reaches the Next.js frontend on port 3000.
  • Terminate TLS at the proxy level using either NGINX with mounted certificates or Traefik with automatic Let's Encrypt provisioning.
  • Update the frontend environment variable NEXT_PUBLIC_API_URL to the public HTTPS origin so the UI correctly routes API calls through the proxy.

Frequently Asked Questions

How do I expose Open Notebook on a subdomain instead of a root domain?

Configure your reverse proxy to route based on the Host header rather than path prefixes. In NGINX, use server_name notebook.example.com; for the frontend and api.notebook.example.com for the backend with separate server blocks. In Traefik, use traefik.http.routers.frontend.rule=Host(\notebook.example.com`)andtraefik.http.routers.api.rule=Host(`api.notebook.example.com`)instead ofPathPrefix` rules.

Why does the frontend show connection errors after setting up the proxy?

The Next.js frontend likely still points to http://localhost:5055 from the default .env.local.example file. You must set NEXT_PUBLIC_API_URL=https://your-domain.com/api in the actual frontend/.env.local file and rebuild the container, as Next.js bakes environment variables into the client bundle at build time rather than runtime.

Does SurrealDB need to be exposed through the reverse proxy?

No, SurrealDB should remain isolated on the internal Docker network and accessible only to the API service. The database on port 8000 does not require external exposure; only the FastAPI backend communicates with it directly. Ensure your docker-compose.yml does not map port 8000 to the host when using a reverse proxy.

Which proxy is better for Open Notebook: NGINX or Traefik?

Traefik simplifies TLS management with automatic Let's Encrypt integration and dynamic service discovery via Docker labels, making it ideal for containerized deployments. NGINX offers more complex configuration options and is preferable if you require specific request manipulation, custom authentication modules, or already operate an NGINX infrastructure. Both handle the WebSocket upgrades required for streaming chat responses in the FastAPI backend.

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 →