feat: simplify reverse proxy configuration with Next.js rewrites (#213)
Some checks are pending
Development Build / extract-version (push) Waiting to run
Development Build / test-build-regular (push) Blocked by required conditions
Development Build / test-build-single (push) Blocked by required conditions
Development Build / summary (push) Blocked by required conditions

* feat: simplify reverse proxy configuration with Next.js rewrites

Add Next.js API rewrites to proxy /api/* requests internally from port 8502
to the FastAPI backend on port 5055. This eliminates the need for complex
reverse proxy configurations with multiple upstreams and location blocks.

Changes:
- Add rewrites to next.config.ts proxying /api/* to INTERNAL_API_URL
- Introduce INTERNAL_API_URL env var (defaults to http://localhost:5055)
- Update supervisord configs to pass INTERNAL_API_URL to Next.js
- Document INTERNAL_API_URL in .env.example with usage examples
- Add simplified reverse proxy examples for nginx, Traefik, Caddy, Coolify
- Update README architecture diagram to show internal proxying
- Add explanatory comments to _config route handler

Benefits:
- Reduces reverse proxy config from 12 lines to 3 (75% reduction)
- Single-port deployment (8502 only) for 95% of use cases
- Zero breaking changes - backward compatible with existing setups
- Zero performance overhead (validated through testing)
- Preserves proxy headers (X-Forwarded-*) for rate limiting/SSL

Resolves: #179
Related: OSS-321

* fix: rename _config to config to fix production routing

CRITICAL BUG FIX: The /_config endpoint has never worked in production builds
because Next.js treats folders starting with underscore as "private folders"
and excludes them from routing entirely.

This endpoint is critical for:
- Providing API_URL to the browser at runtime
- Enabling zero-config deployments with auto-detection
- Supporting reverse proxy scenarios where API URL differs from frontend URL

Changes:
- Rename frontend/src/app/_config/ → frontend/src/app/config/
- Update client code references (/_config → /config)
- Update documentation with correct endpoint path
- Bump version to 1.1.0 (minor version for new rewrites feature + bug fix)

Impact:
- Runtime configuration now works in production builds
- /config returns {"apiUrl":"http://localhost:5055"} correctly
- Auto-detection for reverse proxy deployments now functional

Related: #179, OSS-321

* fix: resolve React hook exhaustive-deps warning in AddExistingSourceDialog

Wrap performSearch function in useCallback to properly memoize it and satisfy
React Hook exhaustive-deps rule. This prevents unnecessary re-renders and
ensures the useEffect dependency array is correctly specified.

Changes:
- Import useCallback from React
- Wrap performSearch with useCallback([debouncedSearchQuery, allSources])
- Add performSearch to useEffect dependency array

* final fixes
This commit is contained in:
Luis Novo 2025-10-24 11:24:14 -03:00 committed by GitHub
parent d680a0affc
commit 9bdfd99f1b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 371 additions and 193 deletions

View file

@ -2,6 +2,120 @@
This guide helps you deploy Open Notebook behind a reverse proxy (nginx, Caddy, Traefik, etc.) or with a custom domain.
## ⭐ Simplified Configuration (v1.1+)
Starting with v1.1, Open Notebook uses Next.js rewrites to dramatically simplify reverse proxy configuration. **You now only need to proxy to port 8502** - Next.js handles internal API routing automatically.
### How It Works
```
Browser → Reverse Proxy → Port 8502 (Next.js)
↓ (internal proxy)
Port 5055 (FastAPI)
```
Next.js rewrites automatically forward `/api/*` requests to the FastAPI backend on port 5055, so your reverse proxy only needs to know about one port!
### Simple 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;
# 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;
}
}
```
#### Traefik
```yaml
services:
open-notebook:
image: lfnovo/open_notebook:v1-latest-single
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"
networks:
- traefik-network
```
#### Caddy
```caddy
notebook.example.com {
reverse_proxy open-notebook:8502
}
```
#### Coolify
1. Create a new service pointing to `lfnovo/open_notebook:v1-latest-single`
2. Set port to **8502** (not 5055!)
3. Add environment variable: `API_URL=https://your-domain.com`
4. Enable HTTPS in Coolify settings
5. Done! Coolify handles the reverse proxy automatically.
### Environment Variables
With the simplified approach, you typically only need:
```bash
# Required for reverse proxy setups
API_URL=https://your-domain.com
# Optional: Only needed for multi-container deployments
# Default is http://localhost:5055 (single-container)
# INTERNAL_API_URL=http://api-service:5055
```
### Optional: Direct API Access for External Integrations
If you have external scripts or integrations that need direct API access, you can still route `/api/*` directly to port 5055:
```nginx
# Optional: Direct API access (for external integrations only)
location /api/ {
proxy_pass http://open-notebook:5055/api/;
# ... same headers as above
}
# Primary route (handles browser traffic)
location / {
proxy_pass http://open-notebook:8502;
# ... same headers as above
}
```
**Note**: The simplified single-port approach (port 8502 only) works for 95% of use cases. Only add direct API routing if you specifically need it.
---
## Legacy Configuration (Pre-v1.1)
> **Note**: The configurations below are still supported but no longer necessary with v1.1+. New deployments should use the simplified configuration above.
## The API_URL Environment Variable
Starting with v1.0+, Open Notebook supports runtime configuration of the API URL through the `API_URL` environment variable. This means you can use the same Docker image in different deployment scenarios without rebuilding.
@ -127,7 +241,7 @@ http {
proxy_set_header X-Forwarded-Proto $scheme;
}
# Frontend (catch-all - handles /_config automatically)
# Frontend (catch-all - handles /config automatically)
location / {
proxy_pass http://frontend;
proxy_http_version 1.1;
@ -223,7 +337,7 @@ notebook.example.com {
# API
reverse_proxy /api/* open-notebook:5055
# Frontend (catch-all - handles /_config automatically)
# Frontend (catch-all - handles /config automatically)
reverse_proxy / open-notebook:8502
}
```
@ -273,15 +387,15 @@ services:
In versions ≤ 1.0.10, the frontend's config endpoint was at `/api/runtime-config`, which gets 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.
Upgrade to version 1.0.11 or later. The config endpoint has been moved to `/config` which avoids the `/api/*` routing conflict.
**Note**: Most reverse proxy configurations with a catch-all rule like `location / { proxy_pass http://frontend; }` will automatically route `/_config` to the frontend without any additional configuration needed.
**Note**: Most reverse proxy configurations with a catch-all rule like `location / { proxy_pass http://frontend; }` will automatically route `/config` to the frontend without any additional configuration needed.
**Only if you have issues**, explicitly configure the `/_config` route:
**Only if you have issues**, explicitly configure the `/config` route:
```nginx
# Only needed if your reverse proxy doesn't have a catch-all rule
location = /_config {
location = /config {
proxy_pass http://open-notebook:8502;
proxy_http_version 1.1;
proxy_set_header Host $host;