How to Configure CORS for Production Deployments in Open Notebook
Set the CORS_ORIGINS environment variable to a comma-separated list of your frontend domains (e.g., https://app.example.com) before starting the API; if unset, Open Notebook defaults to allowing all origins (*), which triggers a security warning at startup and leaves your production deployment vulnerable to cross-origin attacks.
Open Notebook is an open-source knowledge management platform built on FastAPI. Properly configuring CORS for production deployments ensures that only your trusted frontend domains can communicate with the API, preventing unauthorized cross-origin requests while maintaining seamless browser interactions.
Understanding CORS in Open Notebook
Open Notebook's API layer, defined in api/main.py, implements cross-origin resource sharing through FastAPI's CORSMiddleware. The system uses the CORS_ORIGINS environment variable to determine which domains may access API resources from browser contexts.
The CORS_ORIGINS Environment Variable
The application parses CORS_ORIGINS using the internal _parse_cors_origins function, which converts comma-separated origin strings into a Python list. This list is injected directly into FastAPI's CORSMiddleware as the allow_origins parameter. The same origin list is referenced by the custom _cors_headers error handler, ensuring that CORS policy is enforced even on API error responses.
Default Behavior and Security Warnings
When CORS_ORIGINS is unset, the API defaults to allow_origins=["*"], permitting requests from any domain. During startup (typically around lines 63-70 in api/main.py), the application logs a warning reminding administrators to configure explicit origins for production use. According to the project's security documentation in docs/5-CONFIGURATION/security.md, this permissive default is intended only for local development.
Configuring CORS for Production
To secure your deployment, restrict CORS to only the specific origins hosting your frontend applications.
1. Identify Your Frontend Origins
Determine the exact HTTPS origins of your production frontend(s), including protocol and domain. For example: https://app.example.com or https://notebook.example.com.
2. Set the CORS_ORIGINS Variable
Export the environment variable as a comma-separated list without spaces:
export CORS_ORIGINS="https://app.example.com,https://admin.example.com"
The API reads this value only at process startup, so the variable must be present before the server initializes.
3. Restart the API Service
Restart your Open Notebook instance to load the new CORS configuration. The API will now:
- Reflect the
Access-Control-Allow-Originheader only for requests from listed origins - Omit the header entirely for requests from unauthorized domains
- Apply these restrictions consistently across both successful responses and error states
Production Deployment Examples
Docker Compose Configuration
When deploying via Docker Compose, set CORS_ORIGINS in the environment section of your service definition:
services:
open_notebook:
image: lfnovo/open_notebook:v1-latest
ports:
- "8502:8502"
- "5055:5055"
environment:
- OPEN_NOTEBOOK_ENCRYPTION_KEY=change-me-to-a-secret-string
- CORS_ORIGINS=https://app.example.com,https://admin.example.com
- SURREAL_URL=ws://surrealdb:8000/rpc
- SURREAL_USER=root
- SURREAL_PASSWORD=root
- SURREAL_NAMESPACE=open_notebook
- SURREAL_DATABASE=open_notebook
Standalone Uvicorn Deployment
For manual deployments using Uvicorn:
export CORS_ORIGINS="https://app.example.com"
uvicorn api.main:app --host 0.0.0.0 --port 5055
Verifying CORS Configuration with curl
Test that unauthorized origins are blocked while permitted origins receive proper headers:
# Request from authorized origin - should include CORS header
curl -i -H "Origin: https://app.example.com" http://localhost:5055/health
# Expected: Access-Control-Allow-Origin: https://app.example.com
# Request from unauthorized origin - should omit CORS header
curl -i -H "Origin: https://malicious.com" http://localhost:5055/health
# Expected: No Access-Control-Allow-Origin header
Summary
- Open Notebook's CORS policy is controlled by the
CORS_ORIGINSenvironment variable, parsed at startup inapi/main.py. - The default value of
*(allow all origins) triggers a security warning and is unsafe for production use. - Set
CORS_ORIGINSto a comma-separated list of your frontend domains before starting the API. - The configuration applies to both successful API responses and error responses via the
_cors_headershandler. - Changes require a process restart to take effect.
Frequently Asked Questions
What happens if I don't set CORS_ORIGINS in production?
If CORS_ORIGINS is unset, Open Notebook defaults to allowing all origins (*), which exposes your API to cross-origin requests from any domain. The application logs a warning at startup (visible in api/main.py around lines 63-70) alerting you that the permissive default should not be used in production environments.
How do I configure multiple allowed origins?
Set CORS_ORIGINS to a comma-separated list without spaces: https://app.example.com,https://admin.example.com. The internal _parse_cors_origins function in api/main.py splits this string into a list that FastAPI's CORSMiddleware uses to validate incoming requests.
Why are CORS headers missing from error responses?
If you see CORS headers on successful requests but not on errors, ensure CORS_ORIGINS is properly set. Open Notebook implements a custom _cors_headers error handler that consults the same origin list used by the middleware; when the origin is not in the allowed list, the header is intentionally omitted to prevent information leakage across origins.
Does the CORS configuration require an API restart?
Yes. The CORS_ORIGINS value is read only once during process initialization in api/main.py. Any changes to the environment variable require restarting the Open Notebook API service to take effect.
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 →