Spaces:
Paused
Paused
| # Reverse Proxy Configuration | |
| Deploy Open Notebook behind nginx, Caddy, Traefik, or other reverse proxies with custom domains and HTTPS. | |
| --- | |
| ## Simplified Setup (v1.1+) | |
| Starting with v1.1, Open Notebook uses Next.js rewrites to simplify configuration. **You only need to proxy to one port** - Next.js handles internal API routing automatically. | |
| ### How It Works | |
| ``` | |
| Browser → Reverse Proxy → Port 8502 (Next.js) | |
| ↓ (internal proxy) | |
| Port 5055 (FastAPI) | |
| ``` | |
| Next.js automatically forwards `/api/*` requests to the FastAPI backend, so your reverse proxy only needs one port! | |
| --- | |
| ## Quick Configuration Examples | |
| ### Nginx (Recommended) | |
| ```nginx | |
| 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; | |
| # Allow file uploads up to 100MB | |
| client_max_body_size 100M; | |
| # Single location block - that's it! | |
| 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; | |
| } | |
| } | |
| # HTTP to HTTPS redirect | |
| server { | |
| listen 80; | |
| server_name notebook.example.com; | |
| return 301 https://$server_name$request_uri; | |
| } | |
| ``` | |
| ### Caddy | |
| ```caddy | |
| notebook.example.com { | |
| reverse_proxy open-notebook:8502 { | |
| transport http { | |
| read_timeout 600s | |
| write_timeout 600s | |
| } | |
| } | |
| } | |
| ``` | |
| Caddy handles HTTPS automatically. The timeout settings ensure long-running operations (transformations, podcast generation) don't fail. | |
| ### Traefik | |
| ```yaml | |
| # Add this to your docker-compose.yml alongside the surrealdb service | |
| # See full base setup: https://github.com/lfnovo/open-notebook/blob/main/docker-compose.yml | |
| services: | |
| open-notebook: | |
| image: lfnovo/open_notebook:v1-latest | |
| pull_policy: always | |
| 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" | |
| # Timeout for long-running operations (transformations, podcasts) | |
| - "traefik.http.services.notebook.loadbalancer.responseforwarding.flushinterval=100ms" | |
| networks: | |
| - traefik-network | |
| ``` | |
| **Note**: For Traefik v2+, you may also need to configure `serversTransport` timeouts in your static configuration: | |
| ```yaml | |
| # traefik.yml (static configuration) | |
| serversTransport: | |
| forwardingTimeouts: | |
| dialTimeout: 30s | |
| responseHeaderTimeout: 600s | |
| idleConnTimeout: 90s | |
| ``` | |
| ### Coolify | |
| 1. Create new service using [Docker Compose](../1-INSTALLATION/docker-compose.md) | |
| 2. Set port to **8502** | |
| 3. Add environment: `API_URL=https://your-domain.com` | |
| 4. Enable HTTPS in Coolify | |
| 5. Done! | |
| --- | |
| ## Environment Variables | |
| ```bash | |
| # Required for reverse proxy setups | |
| API_URL=https://your-domain.com | |
| # Optional: For multi-container deployments | |
| # INTERNAL_API_URL=http://api-service:5055 | |
| ``` | |
| **Important**: Set `API_URL` to your public URL (with https://). | |
| **Note on HOSTNAME**: The Docker images set `HOSTNAME=0.0.0.0` by default, which ensures Next.js binds to all interfaces and is accessible from reverse proxies. You typically don't need to set this manually. | |
| --- | |
| ## Understanding API_URL | |
| The frontend uses a three-tier priority system to determine the API URL: | |
| 1. **Runtime Configuration** (Highest Priority): `API_URL` environment variable set at container runtime | |
| 2. **Build-time Configuration**: `NEXT_PUBLIC_API_URL` baked into the Docker image | |
| 3. **Auto-detection** (Fallback): Infers from the incoming HTTP request headers | |
| ### Auto-Detection Details | |
| When `API_URL` is not set, the Next.js frontend: | |
| - Analyzes the incoming HTTP request | |
| - Extracts the hostname from the `host` header | |
| - Respects the `X-Forwarded-Proto` header (for HTTPS behind reverse proxies) | |
| - Constructs the API URL as `{protocol}://{hostname}:5055` | |
| - Example: Request to `http://10.20.30.20:8502` → API URL becomes `http://10.20.30.20:5055` | |
| **Why set API_URL explicitly?** | |
| - **Reliability**: Auto-detection can fail with complex proxy setups | |
| - **HTTPS**: Ensures frontend uses `https://` when behind SSL-terminating proxy | |
| - **Custom domains**: Works correctly with domain names instead of IP addresses | |
| - **Port mapping**: Avoids exposing port 5055 in the URL when using reverse proxy | |
| **Important**: Don't include `/api` at the end - the system adds this automatically! | |
| --- | |
| ## Complete Docker Compose Example | |
| > **Note:** This example only shows the open-notebook and nginx services. You also need a `surrealdb` service. See the [full base docker-compose.yml](https://github.com/lfnovo/open-notebook/blob/main/docker-compose.yml) for the complete setup. | |
| ```yaml | |
| services: | |
| open-notebook: | |
| image: lfnovo/open_notebook:v1-latest | |
| pull_policy: always | |
| container_name: open-notebook | |
| environment: | |
| - API_URL=https://notebook.example.com | |
| - OPEN_NOTEBOOK_ENCRYPTION_KEY=${OPEN_NOTEBOOK_ENCRYPTION_KEY} | |
| - OPEN_NOTEBOOK_PASSWORD=${OPEN_NOTEBOOK_PASSWORD} | |
| volumes: | |
| - ./notebook_data:/app/data | |
| # Only expose to localhost (nginx handles public access) | |
| ports: | |
| - "127.0.0.1:8502:8502" | |
| restart: unless-stopped | |
| nginx: | |
| image: nginx:alpine | |
| container_name: nginx-proxy | |
| ports: | |
| - "80:80" | |
| - "443:443" | |
| volumes: | |
| - ./nginx.conf:/etc/nginx/nginx.conf:ro | |
| - ./ssl:/etc/nginx/ssl:ro | |
| depends_on: | |
| - open-notebook | |
| restart: unless-stopped | |
| ``` | |
| --- | |
| ## Full Nginx Configuration | |
| ```nginx | |
| events { | |
| worker_connections 1024; | |
| } | |
| http { | |
| upstream notebook { | |
| server open-notebook:8502; | |
| } | |
| # HTTP redirect | |
| server { | |
| listen 80; | |
| server_name notebook.example.com; | |
| return 301 https://$server_name$request_uri; | |
| } | |
| # HTTPS server | |
| 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; | |
| # Allow file uploads up to 100MB | |
| client_max_body_size 100M; | |
| # Security headers | |
| 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"; | |
| # Proxy settings | |
| 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; | |
| # Timeouts for long-running operations (transformations, podcasts, etc.) | |
| # 600s matches the frontend timeout for slow LLM operations | |
| proxy_read_timeout 600s; | |
| proxy_connect_timeout 60s; | |
| proxy_send_timeout 600s; | |
| } | |
| } | |
| } | |
| ``` | |
| --- | |
| ## Direct API Access (Optional) | |
| If external scripts or integrations need direct API access, route `/api/*` directly: | |
| ```nginx | |
| # Direct API access (for external integrations) | |
| location /api/ { | |
| proxy_pass http://open-notebook:5055/api/; | |
| 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; | |
| } | |
| # Frontend (handles all other traffic) | |
| location / { | |
| proxy_pass http://open-notebook:8502; | |
| # ... same headers as above | |
| } | |
| ``` | |
| **Note**: This is only needed for external API integrations. Browser traffic works fine with single-port setup. | |
| --- | |
| ## Advanced Scenarios | |
| ### Remote Server Access (LAN/VPS) | |
| Accessing Open Notebook from a different machine on your network: | |
| **Step 1: Get your server IP** | |
| ```bash | |
| # On the server running Open Notebook: | |
| hostname -I | |
| # or | |
| ifconfig | grep "inet " | |
| # Note the IP (e.g., 192.168.1.100) | |
| ``` | |
| **Step 2: Configure API_URL** | |
| ```bash | |
| # In docker-compose.yml or .env: | |
| API_URL=http://192.168.1.100:5055 | |
| ``` | |
| **Step 3: Expose ports** | |
| ```yaml | |
| # Add to your docker-compose.yml (requires surrealdb service, see installation guide) | |
| services: | |
| open-notebook: | |
| image: lfnovo/open_notebook:v1-latest | |
| pull_policy: always | |
| environment: | |
| - API_URL=http://192.168.1.100:5055 | |
| ports: | |
| - "8502:8502" | |
| - "5055:5055" | |
| ``` | |
| **Step 4: Access from client machine** | |
| ```bash | |
| # In browser on other machine: | |
| http://192.168.1.100:8502 | |
| ``` | |
| **Troubleshooting**: | |
| - Check firewall: `sudo ufw allow 8502 && sudo ufw allow 5055` | |
| - Verify connectivity: `ping 192.168.1.100` from client machine | |
| - Test port: `telnet 192.168.1.100 8502` from client machine | |
| --- | |
| ### API on Separate Subdomain | |
| Host the API and frontend on different subdomains: | |
| **docker-compose.yml:** | |
| ```yaml | |
| # Add to your docker-compose.yml (requires surrealdb service, see installation guide) | |
| services: | |
| open-notebook: | |
| image: lfnovo/open_notebook:v1-latest | |
| pull_policy: always | |
| environment: | |
| - API_URL=https://api.notebook.example.com | |
| - OPEN_NOTEBOOK_ENCRYPTION_KEY=${OPEN_NOTEBOOK_ENCRYPTION_KEY} | |
| # Don't expose ports (nginx handles routing) | |
| ``` | |
| **nginx.conf:** | |
| ```nginx | |
| # Frontend server | |
| 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; | |
| 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; | |
| } | |
| } | |
| # API server (separate subdomain) | |
| server { | |
| listen 443 ssl http2; | |
| server_name api.notebook.example.com; | |
| ssl_certificate /etc/nginx/ssl/fullchain.pem; | |
| ssl_certificate_key /etc/nginx/ssl/privkey.pem; | |
| location / { | |
| proxy_pass http://open-notebook:5055; | |
| 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; | |
| } | |
| } | |
| ``` | |
| **Use case**: Separate DNS records, different rate limiting, or isolated API access control. | |
| --- | |
| ### Multi-Container Deployment (Advanced) | |
| For complex deployments with separate frontend and API containers: | |
| **docker-compose.yml:** | |
| ```yaml | |
| services: | |
| frontend: | |
| image: lfnovo/open_notebook_frontend:v1-latest | |
| pull_policy: always | |
| environment: | |
| - API_URL=https://notebook.example.com | |
| ports: | |
| - "8502:8502" | |
| api: | |
| image: lfnovo/open_notebook_api:v1-latest | |
| pull_policy: always | |
| environment: | |
| - OPEN_NOTEBOOK_ENCRYPTION_KEY=${OPEN_NOTEBOOK_ENCRYPTION_KEY} | |
| ports: | |
| - "5055:5055" | |
| depends_on: | |
| - surrealdb | |
| surrealdb: | |
| image: surrealdb/surrealdb:latest | |
| command: start --log trace --user root --pass root file:/mydata/database.db | |
| ports: | |
| - "8000:8000" | |
| volumes: | |
| - ./surreal_data:/mydata | |
| ``` | |
| **nginx.conf:** | |
| ```nginx | |
| http { | |
| upstream frontend { | |
| server frontend:8502; | |
| } | |
| upstream api { | |
| server api:5055; | |
| } | |
| server { | |
| listen 443 ssl http2; | |
| server_name notebook.example.com; | |
| # API routes | |
| location /api/ { | |
| proxy_pass http://api/api/; | |
| 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; | |
| } | |
| # Frontend (catch-all) | |
| location / { | |
| proxy_pass http://frontend; | |
| 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; | |
| } | |
| } | |
| } | |
| ``` | |
| **Note**: Most users should use the [Docker Compose](../1-INSTALLATION/docker-compose.md) approach (`v1-latest`). Multi-container with separate nginx is only needed for custom scaling or isolation requirements. | |
| --- | |
| ## SSL Certificates | |
| ### Let's Encrypt with Certbot | |
| ```bash | |
| # Install certbot | |
| sudo apt install certbot python3-certbot-nginx | |
| # Get certificate | |
| sudo certbot --nginx -d notebook.example.com | |
| # Auto-renewal (usually configured automatically) | |
| sudo certbot renew --dry-run | |
| ``` | |
| ### Let's Encrypt with Caddy | |
| Caddy handles SSL automatically - no configuration needed! | |
| ### Self-Signed (Development Only) | |
| ```bash | |
| openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ | |
| -keyout ssl/privkey.pem \ | |
| -out ssl/fullchain.pem \ | |
| -subj "/CN=localhost" | |
| ``` | |
| --- | |
| ## Troubleshooting | |
| ### "Unable to connect to server" | |
| 1. **Check API_URL is set**: | |
| ```bash | |
| docker exec open-notebook env | grep API_URL | |
| ``` | |
| 2. **Verify reverse proxy reaches container**: | |
| ```bash | |
| curl -I http://localhost:8502 | |
| ``` | |
| 3. **Check browser console** (F12): | |
| - Look for connection errors | |
| - Check what URL it's trying to reach | |
| ### Mixed Content Errors | |
| Frontend using HTTPS but trying to reach HTTP API: | |
| ```bash | |
| # Ensure API_URL uses https:// | |
| API_URL=https://notebook.example.com # Not http:// | |
| ``` | |
| ### WebSocket Issues | |
| Ensure your proxy supports WebSocket upgrades: | |
| ```nginx | |
| proxy_http_version 1.1; | |
| proxy_set_header Upgrade $http_upgrade; | |
| proxy_set_header Connection 'upgrade'; | |
| ``` | |
| ### 502 Bad Gateway | |
| 1. Check container is running: `docker ps` | |
| 2. Check container logs: `docker logs open-notebook` | |
| 3. Verify nginx can reach container (same network) | |
| ### Timeout Errors | |
| **Symptoms:** | |
| - `socket hang up` or `ECONNRESET` errors | |
| - `Timeout after 30000ms` errors | |
| - Operations fail after exactly 30 seconds | |
| **Cause:** Your reverse proxy has a default timeout (often 30s) that's shorter than Open Notebook's operations. | |
| **Solutions by proxy:** | |
| **Nginx:** | |
| ```nginx | |
| proxy_read_timeout 600s; | |
| proxy_send_timeout 600s; | |
| ``` | |
| **Caddy:** | |
| ```caddy | |
| reverse_proxy open-notebook:8502 { | |
| transport http { | |
| read_timeout 600s | |
| write_timeout 600s | |
| } | |
| } | |
| ``` | |
| **Traefik (static config):** | |
| ```yaml | |
| serversTransport: | |
| forwardingTimeouts: | |
| responseHeaderTimeout: 600s | |
| ``` | |
| **Application-level timeouts:** | |
| If you still experience timeouts after configuring your proxy, you can also adjust the application timeouts: | |
| ```bash | |
| # In .env file: | |
| API_CLIENT_TIMEOUT=600 # API client timeout (default: 300s) | |
| ESPERANTO_LLM_TIMEOUT=180 # LLM inference timeout (default: 60s) | |
| ``` | |
| See [Advanced Configuration](advanced.md) for more timeout options. | |
| --- | |
| ### How to Debug Configuration Issues | |
| **Step 1: Check browser console** (F12 → Console tab) | |
| ``` | |
| Look for messages starting with 🔧 [Config] | |
| These show the configuration detection process | |
| You'll see which API URL is being used | |
| ``` | |
| **Example good output:** | |
| ``` | |
| ✅ [Config] Runtime API URL from server: https://your-domain.com | |
| ``` | |
| **Example bad output:** | |
| ``` | |
| ❌ [Config] Failed to fetch runtime config | |
| ⚠️ [Config] Using auto-detected URL: http://localhost:5055 | |
| ``` | |
| **Step 2: Test API directly** | |
| ```bash | |
| # Should return JSON config | |
| curl https://your-domain.com/api/config | |
| # Expected output: | |
| {"status":"ok","credentials_configured":true,...} | |
| ``` | |
| **Step 3: Check Docker logs** | |
| ```bash | |
| docker logs open-notebook | |
| # Look for: | |
| # - Frontend startup: "▲ Next.js ready on http://0.0.0.0:8502" | |
| # - API startup: "INFO: Uvicorn running on http://0.0.0.0:5055" | |
| # - Connection errors or CORS issues | |
| ``` | |
| **Step 4: Verify environment variable** | |
| ```bash | |
| docker exec open-notebook env | grep API_URL | |
| # Should show: | |
| # API_URL=https://your-domain.com | |
| ``` | |
| --- | |
| ### Frontend Adds `:5055` to URL (Versions ≤ 1.0.10) | |
| **Symptoms** (only in older versions): | |
| - You set `API_URL=https://your-domain.com` | |
| - Browser console shows: "Attempted URL: https://your-domain.com:5055/api/config" | |
| - CORS errors with "Status code: (null)" | |
| **Root Cause:** | |
| In versions ≤ 1.0.10, the frontend's config endpoint was at `/api/runtime-config`, which got intercepted by reverse proxies routing all `/api/*` requests to the backend. This prevented the frontend from reading the `API_URL` environment variable. | |
| **Solution:** | |
| Upgrade to version 1.0.11 or later. The config endpoint has been moved to `/config` which avoids the `/api/*` routing conflict. | |
| **Verification:** | |
| Check browser console (F12) - should see: `✅ [Config] Runtime API URL from server: https://your-domain.com` | |
| **If you can't upgrade**, explicitly configure the `/config` route: | |
| ```nginx | |
| # Only needed for versions ≤ 1.0.10 | |
| location = /config { | |
| proxy_pass http://open-notebook:8502; | |
| proxy_http_version 1.1; | |
| proxy_set_header Host $host; | |
| proxy_set_header X-Forwarded-Proto $scheme; | |
| } | |
| ``` | |
| --- | |
| ### File Upload Errors (413 Payload Too Large) | |
| **Symptoms:** | |
| ``` | |
| CORS header 'Access-Control-Allow-Origin' missing. Status code: 413. | |
| Error creating source. Please try again. | |
| ``` | |
| **Root Cause:** | |
| When uploading files, your reverse proxy may reject the request due to body size limits *before* it reaches the application. Since the error happens at the proxy level, CORS headers are not included in the response. | |
| **Version Requirement:** | |
| - **Open Notebook v1.3.2+** is required for file uploads >10MB | |
| - Uses Next.js 16+ which supports the `proxyClientMaxBodySize` configuration option | |
| - Check your version: Settings → About (bottom of settings page) | |
| **Solutions:** | |
| 1. **Nginx - Increase body size limit**: | |
| ```nginx | |
| server { | |
| # Allow larger file uploads (default is 1MB) | |
| client_max_body_size 100M; | |
| # Add CORS headers to error responses | |
| error_page 413 = @cors_error_413; | |
| location @cors_error_413 { | |
| add_header 'Access-Control-Allow-Origin' '*' always; | |
| add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always; | |
| add_header 'Access-Control-Allow-Headers' '*' always; | |
| return 413 '{"detail": "File too large. Maximum size is 100MB."}'; | |
| } | |
| location / { | |
| # ... your existing proxy configuration | |
| } | |
| } | |
| ``` | |
| 2. **Traefik - Increase buffer size**: | |
| ```yaml | |
| # In your traefik configuration | |
| http: | |
| middlewares: | |
| large-body: | |
| buffering: | |
| maxRequestBodyBytes: 104857600 # 100MB | |
| ``` | |
| Apply middleware to your router: | |
| ```yaml | |
| labels: | |
| - "traefik.http.routers.notebook.middlewares=large-body" | |
| ``` | |
| 3. **Kubernetes Ingress (nginx-ingress)**: | |
| ```yaml | |
| apiVersion: networking.k8s.io/v1 | |
| kind: Ingress | |
| metadata: | |
| name: open-notebook | |
| annotations: | |
| nginx.ingress.kubernetes.io/proxy-body-size: "100m" | |
| # Add CORS headers for error responses | |
| nginx.ingress.kubernetes.io/configuration-snippet: | | |
| more_set_headers "Access-Control-Allow-Origin: *"; | |
| ``` | |
| 4. **Caddy**: | |
| ```caddy | |
| notebook.example.com { | |
| request_body { | |
| max_size 100MB | |
| } | |
| reverse_proxy open-notebook:8502 { | |
| transport http { | |
| read_timeout 600s | |
| write_timeout 600s | |
| } | |
| } | |
| } | |
| ``` | |
| **Note:** Open Notebook's API includes CORS headers in error responses, but this only works for errors that reach the application. Proxy-level errors (like 413 from nginx) need to be configured at the proxy level. | |
| --- | |
| ### CORS Errors | |
| **Symptoms:** | |
| ``` | |
| Access-Control-Allow-Origin header is missing | |
| Cross-Origin Request Blocked | |
| Response to preflight request doesn't pass access control check | |
| ``` | |
| **Possible Causes:** | |
| 1. **Missing proxy headers**: | |
| ```nginx | |
| # Make sure these are set: | |
| proxy_set_header X-Forwarded-Proto $scheme; | |
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |
| proxy_set_header Host $host; | |
| ``` | |
| 2. **API_URL protocol mismatch**: | |
| ```bash | |
| # Frontend is HTTPS, but API_URL is HTTP: | |
| API_URL=http://notebook.example.com # ❌ Wrong | |
| API_URL=https://notebook.example.com # ✅ Correct | |
| ``` | |
| 3. **Reverse proxy not forwarding `/api/*` correctly**: | |
| ```nginx | |
| # Make sure this works: | |
| location /api/ { | |
| proxy_pass http://open-notebook:5055/api/; # Note the trailing slash! | |
| } | |
| ``` | |
| --- | |
| ### Missing Authorization Header | |
| **Symptoms:** | |
| ```json | |
| {"detail": "Missing authorization header"} | |
| ``` | |
| This happens when: | |
| - You have set `OPEN_NOTEBOOK_PASSWORD` for authentication | |
| - You're trying to access `/api/config` directly without logging in first | |
| **Solution:** | |
| This is **expected behavior**! The frontend handles authentication automatically. Just: | |
| 1. Access the frontend URL (not `/api/` directly) | |
| 2. Log in through the UI | |
| 3. The frontend will handle authorization headers for all API calls | |
| **For API integrations:** Include the password in the Authorization header: | |
| ```bash | |
| curl -H "Authorization: Bearer your-password-here" \ | |
| https://your-domain.com/api/config | |
| ``` | |
| --- | |
| ### SSL/TLS Certificate Errors | |
| **Symptoms:** | |
| - Browser shows "Your connection is not private" | |
| - Certificate warnings | |
| - Mixed content errors | |
| **Solutions:** | |
| 1. **Use Let's Encrypt** (recommended): | |
| ```bash | |
| sudo certbot --nginx -d notebook.example.com | |
| ``` | |
| 2. **Check certificate paths** in nginx: | |
| ```nginx | |
| ssl_certificate /etc/nginx/ssl/fullchain.pem; # Full chain | |
| ssl_certificate_key /etc/nginx/ssl/privkey.pem; # Private key | |
| ``` | |
| 3. **Verify certificate is valid**: | |
| ```bash | |
| openssl x509 -in /etc/nginx/ssl/fullchain.pem -text -noout | |
| ``` | |
| 4. **For development**, use self-signed (not for production): | |
| ```bash | |
| openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ | |
| -keyout ssl/privkey.pem -out ssl/fullchain.pem \ | |
| -subj "/CN=localhost" | |
| ``` | |
| --- | |
| ## Best Practices | |
| 1. **Always use HTTPS** in production | |
| 2. **Set API_URL explicitly** when using reverse proxies to avoid auto-detection issues | |
| 3. **Bind to localhost** (`127.0.0.1:8502`) and let proxy handle public access for security | |
| 4. **Enable security headers** (HSTS, X-Frame-Options, X-Content-Type-Options, X-XSS-Protection) | |
| 5. **Set up certificate renewal** for Let's Encrypt (usually automatic with certbot) | |
| 6. **Keep ports 5055 and 8502 accessible** from your reverse proxy container (use Docker networks) | |
| 7. **Use environment files** (`.env` or `docker.env`) to manage configuration securely | |
| 8. **Test your configuration** before going live: | |
| - Check browser console for config messages | |
| - Test API: `curl https://your-domain.com/api/config` | |
| - Verify authentication works | |
| - Check long-running operations (podcast generation) | |
| 9. **Monitor logs** regularly: `docker logs open-notebook` | |
| 10. **Don't include `/api` in API_URL** - the system adds this automatically | |
| --- | |
| ## Legacy Configurations (Pre-v1.1) | |
| If you're running Open Notebook **version 1.0.x or earlier**, you may need to use the legacy two-port configuration where you explicitly route `/api/*` to port 5055. | |
| **Check your version:** | |
| ```bash | |
| docker exec open-notebook cat /app/package.json | grep version | |
| ``` | |
| **If version < 1.1.0**, you may need: | |
| - Explicit `/api/*` routing to port 5055 in reverse proxy | |
| - Explicit `/config` endpoint routing for versions ≤ 1.0.10 | |
| - See the "Frontend Adds `:5055` to URL" troubleshooting section above | |
| **Recommendation:** Upgrade to v1.1+ for simplified configuration and better performance. | |
| --- | |
| ## Related | |
| - **[Security Configuration](security.md)** - Password protection and hardening | |
| - **[Advanced Configuration](advanced.md)** - Ports, timeouts, and SSL settings | |
| - **[Troubleshooting](../6-TROUBLESHOOTING/connection-issues.md)** - Connection problems | |
| - **[Docker Deployment](../1-INSTALLATION/docker-compose.md)** - Complete deployment guide | |