# How to Configure CORS Origins for Production Reverse Proxy in Open Notebook

> Secure your Open Notebook production environment by correctly configuring CORS origins for your reverse proxy. Learn how to set trusted domains and ensure CORS headers are forwarded.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-07-05

---

**Set the `CORS_ORIGINS` environment variable to a comma-separated list of trusted domains before starting the Open Notebook API, and ensure your reverse proxy forwards CORS headers on error responses.**

Open Notebook is a FastAPI-based application that relies on environment variables to control cross-origin resource sharing (CORS) behavior. Properly configuring CORS origins is essential when deploying behind a production reverse proxy to prevent browser security errors while maintaining strict access control.

## How CORS Origins Are Parsed in Open Notebook

### Environment Variable Handling

In [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py), the application reads allowed origins from the `CORS_ORIGINS` environment variable (lines 54-66). If this variable is unset, the system defaults to a permissive wildcard (`*`), which explicitly logs a warning that unrestricted access is enabled.

### The Parsing Logic

The helper function `_parse_cors_origins` processes the raw string value by splitting on commas and trimming whitespace (lines 54-60). This converts a comma-separated list into a Python list of origin strings suitable for FastAPI's middleware.

```python
def _parse_cors_origins(raw: str) -> list[str]:
    """Parse CORS_ORIGINS env value into a list of origins."""
    value = raw.strip()
    if value == "*":
        return ["*"]
    return [origin.strip() for origin in value.split(",") if origin.strip()]

```

### Middleware Registration Order

The `CORSMiddleware` is added to the FastAPI application instance using the parsed origins list. According to the source code in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) (lines 37-44), the middleware is registered **last** in the stack so it processes requests first, with credentials, methods, and headers all permitted.

```python
app.add_middleware(
    CORSMiddleware,
    allow_origins=CORS_ALLOWED_ORIGINS,   # Parsed from CORS_ORIGINS

    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

```

## Configuring CORS_ORIGINS for Production Deployment

To restrict cross-origin access to specific domains when running Open Notebook behind nginx, Traefik, or another reverse proxy:

1. **Define the environment variable** in your `.env` file or deployment configuration.
2. **Set the value** to a comma-separated list of trusted origins: `https://notebook.example.com,https://app.example.com`.
3. **Restart the API service**, as the origin list is parsed once at module load time.

```bash

# .env

CORS_ORIGINS=https://notebook.example.com,https://app.example.com

```

## Reverse Proxy Configuration for CORS Error Responses

When Open Notebook runs behind a reverse proxy, the proxy may return HTTP 413 (Payload Too Large) or other errors before the request reaches FastAPI. In these cases, browsers block the response body if CORS headers are missing.

Configure your reverse proxy to add `Access-Control-Allow-Origin` headers to error responses. The following nginx configuration intercepts 413 errors and injects the necessary headers, as referenced in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) (lines 255-257):

```nginx
server {
    listen 80;
    server_name notebook.example.com;

    location / {
        proxy_pass http://localhost:5055;
        proxy_set_header Origin $http_origin;
        proxy_intercept_errors on;
        error_page 413 = @cors_error;
    }

    location @cors_error {
        add_header Access-Control-Allow-Origin $http_origin always;
        add_header Access-Control-Allow-Credentials true always;
        add_header Access-Control-Allow-Methods * always;
        add_header Access-Control-Allow-Headers * always;
        return 413;
    }
}

```

## Summary

- Open Notebook reads CORS origins from the `CORS_ORIGINS` environment variable, falling back to wildcard (`*`) if unset.
- The `_parse_cors_origins` function in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) handles comma-separated domain lists by trimming whitespace and splitting on commas.
- The `CORSMiddleware` is registered last in the FastAPI app to ensure it processes requests before other middleware.
- Production reverse proxies must forward CORS headers on error responses (like HTTP 413) to prevent browsers from blocking error details.

## Frequently Asked Questions

### What happens if I don't set CORS_ORIGINS?

If the `CORS_ORIGINS` environment variable is not defined, Open Notebook defaults to allowing all origins (`*`). This configuration is explicitly logged as a warning in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) (lines 54-66). While this works for local development, it creates security vulnerabilities in production environments.

### Can I use wildcards in the CORS_ORIGINS list?

Yes. Setting `CORS_ORIGINS=*` configures the middleware to accept requests from any origin. However, when credentials are enabled (as they are by default in Open Notebook), modern browsers reject wildcard origins for authenticated requests, making explicit domain configuration necessary for production use.

### Why does my browser still block requests when the proxy returns a 413 error?

Reverse proxies like nginx often return HTTP 413 (Payload Too Large) before the request reaches FastAPI. Since the error response originates from the proxy rather than Open Notebook, it lacks CORS headers. You must configure `proxy_intercept_errors` and an error handler in nginx to inject `Access-Control-Allow-Origin` headers, as documented in the source code comments at [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) lines 255-257.

### Do I need to restart the API after changing CORS_ORIGINS?

Yes. The CORS origin list is parsed from the environment variable once when the module loads at startup. Any changes to `CORS_ORIGINS` require a full restart of the Open Notebook API service to take effect.