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
5055that manages notebook logic, source documents, and chat interactions. - Database: SurrealDB on port
8000for 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
frontendandapiservices indocker-compose.ymlto prevent direct external access. - Configure path-based routing so that
/api/*requests reach the FastAPI service on port5055and all other traffic reaches the Next.js frontend on port3000. - 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_URLto 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →