Configuring Reverse Proxy with CORS Settings for Open Notebook
Open Notebook requires only a single reverse proxy entry pointing to port 8502, with CORS origins controlled via the CORS_ORIGINS environment variable parsed in api/main.py and enforced by FastAPI's CORSMiddleware.
When deploying the lfnovo/open-notebook repository behind a reverse proxy, configuring reverse proxy with CORS settings correctly ensures secure browser communication between the Next.js frontend and FastAPI backend. The application uses a single-port architecture where the frontend handles internal API routing, simplifying proxy configuration while requiring proper origin header forwarding.
Understanding the Single-Port Architecture
Open Notebook runs two services: a FastAPI backend on port 5055 and a Next.js frontend on port 8502. When placing a reverse proxy in front of the application, you only need to forward traffic to the frontend port 8502. The frontend internally routes /api/* requests to the backend, eliminating the need for separate proxy routes or path-based routing rules.
How CORS Is Handled in Open Notebook
Development vs Production Settings
In api/main.py, the application reads the CORS_ORIGINS environment variable at startup to configure CORS behavior:
- Development: When
CORS_ORIGINSis unset, the API accepts any origin ("*"), allowing local development without configuration. - Production: Set
CORS_ORIGINSto a comma-separated list of allowed origins (e.g.,https://notebook.example.com). The application logs a warning if this variable is missing in production environments.
Implementation Details in api/main.py
The CORS implementation in api/main.py uses FastAPI's CORSMiddleware with a custom exception handler to ensure CORS headers appear even on error responses:
# From api/main.py - CORSMiddleware configuration
app.add_middleware(
CORSMiddleware,
allow_origins=CORS_ALLOWED_ORIGINS, # Parsed from CORS_ORIGINS env var
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
The custom exception handler injects CORS headers into HTTP error responses, preventing browsers from blocking error details due to missing Access-Control-Allow-Origin headers.
Reverse Proxy Configuration Examples
Configure your reverse proxy to forward the original Origin header unchanged and point to port 8502.
nginx (Recommended)
The following configuration handles WebSocket upgrades for real-time features and sets appropriate body size limits for file uploads:
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;
client_max_body_size 100M;
location / {
proxy_pass http://open-notebook:8502;
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;
}
}
Caddy (Automatic HTTPS)
notebook.example.com {
reverse_proxy open-notebook:8502 {
transport http {
read_timeout 600s
write_timeout 600s
}
}
}
Traefik (Docker Compose)
services:
open-notebook:
image: lfnovo/open_notebook:v1-latest
environment:
- API_URL=https://notebook.example.com
labels:
- "traefik.enable=true"
- "traefik.http.routers.notebook.rule=Host(`notebook.example.com`)"
- "traefik.http.routers.notebook.entrypoints=websecure"
- "traefik.http.routers.notebook.tls.certresolver=myresolver"
- "traefik.http.services.notebook.loadbalancer.server.port=8502"
Environment Variables for CORS
Configure these variables in your .env file or container environment according to the reference in docs/5-CONFIGURATION/environment-reference.md:
# .env.example
CORS_ORIGINS=https://notebook.example.com,https://admin.example.com
API_URL=https://notebook.example.com
CORS_ORIGINS: Controls which origins the FastAPI backend accepts. Leave unset only for local development according to the source code inapi/main.py.API_URL: Sets the public URL for the Next.js frontend, required when the reverse proxy hides the backend ports.
Handling Proxy-Generated Errors
While Open Notebook's api/main.py handles CORS for application errors, your reverse proxy must add CORS headers to errors it generates itself, such as 413 Payload Too Large. In nginx, configure an error page location:
error_page 413 = @cors_error;
location @cors_error {
add_header Access-Control-Allow-Origin "*";
return 413;
}
This ensures browsers can read error messages when uploads exceed the client_max_body_size limit.
Summary
- Point your reverse proxy to port 8502 only; the frontend handles
/api/*routing internally to the backend on port 5055. - Set
CORS_ORIGINSto a comma-separated list of allowed domains in production; leave unset for development wildcard access. - Ensure the proxy forwards the
Originheader unchanged soCORSMiddlewareinapi/main.pycan validate requests. - Add CORS headers to proxy-generated error responses (like 413) to prevent browser blocking of error details.
- Reference
docs/5-CONFIGURATION/reverse-proxy.mdanddocs/5-CONFIGURATION/environment-reference.mdfor additional configuration options.
Frequently Asked Questions
Do I need to expose port 5055 through the reverse proxy?
No. The FastAPI backend on port 5055 should never be exposed directly to the internet. Configure your reverse proxy to forward only to port 8502, where the Next.js frontend internally handles API requests to the backend.
What happens if I don't set CORS_ORIGINS in production?
If CORS_ORIGINS is unset, api/main.py defaults to allowing all origins ("*"), which creates a security vulnerability in production. The application logs a startup warning when this variable is missing, but you should explicitly set allowed origins before deploying.
Why am I getting CORS errors on large file uploads?
If you see CORS errors specifically when uploading large files, your reverse proxy is likely returning a 413 Payload Too Large error without CORS headers. Add an error handler to your proxy configuration to inject Access-Control-Allow-Origin headers on proxy-generated errors, or increase the client_max_body_size to accommodate your uploads.
Can I use different domains for the frontend and API?
While the frontend and API run on separate ports internally, they should share the same public domain behind the reverse proxy. The API_URL environment variable tells the frontend its public address, but the browser sees all traffic coming from your single domain, eliminating cross-origin issues between the user and the application.
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 →