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 600sandproxy_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_URLto your public HTTPS domain to ensure proper URL generation in the frontend - Increase
client_max_body_sizeto at least100Mfor file uploads - Set
proxy_read_timeoutandproxy_send_timeoutto600sfor long-running AI operations - Never expose port
5055directly; 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →