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-Origin header 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_ORIGINS environment variable, parsed at startup in api/main.py.
  • The default value of * (allow all origins) triggers a security warning and is unsafe for production use.
  • Set CORS_ORIGINS to 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_headers handler.
  • 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:

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 →