Security Best Practices for Deploying Open Notebook Publicly: A Production Hardening Guide
Deploy Open Notebook behind a reverse proxy with HTTPS, bind the frontend to localhost only, store secrets using Docker secrets or encrypted env files, and configure strict CORS and security headers to protect the FastAPI backend and encrypted credentials.
Open Notebook is a privacy-first research assistant that encrypts sensitive provider API keys using Fernet encryption. When exposing the application to the Internet, administrators must harden both the Next.js frontend and FastAPI backend according to the security documentation in docs/5-CONFIGURATION/security.md and docs/5-CONFIGURATION/reverse-proxy.md.
Encrypt and Protect Credentials
Open Notebook derives a Fernet encryption key from the OPEN_NOTEBOOK_ENCRYPTION_KEY environment variable using SHA-256 and uses it to secure all stored LLM API keys in open_notebook/ai/…. Never commit this key to version control, and use Docker secrets or a secure vault in production.
Set a strong OPEN_NOTEBOOK_PASSWORD with 20+ characters of high entropy. The frontend automatically sends this via Authorization: Bearer <password> headers to authenticate requests. For production, mount secrets as files rather than environment variables:
environment:
- OPEN_NOTEBOOK_PASSWORD_FILE=/run/secrets/app_password
- OPEN_NOTEBOOK_ENCRYPTION_KEY_FILE=/run/secrets/encryption_key
Critical: Back up the encryption key separately from the database. Rotating it without re-saving all API keys will render stored credentials unrecoverable, as noted in docs/5-CONFIGURATION/security.md.
Run Behind a Reverse Proxy and Enforce HTTPS
The reverse proxy terminates TLS, hides internal ports, and injects security headers. The frontend runs on port 8502, while the FastAPI backend listens on port 5055 and should never be exposed publicly—the Next.js frontend automatically routes /api/* traffic to the backend internally.
Nginx Configuration
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;
client_max_body_size 100M;
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;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}
Caddy (Auto-TLS)
notebook.example.com {
reverse_proxy open-notebook:8502 {
transport http {
read_timeout 600s
write_timeout 600s
}
}
}
Traefik (Docker Labels)
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"
Restrict Network Access
Bind the frontend container to localhost only to prevent direct external access, forcing all traffic through the reverse proxy.
ports:
- "127.0.0.1:8502:8502"
Block the FastAPI backend port from the public Internet using firewall rules:
# Block direct access to backend
iptables -A INPUT -p tcp --dport 5055 -j DROP
# Allow only necessary ports
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
Place the SurrealDB container (port 8000) on a private Docker network unreachable from the proxy to implement network segmentation.
Lock Down CORS Configuration
By default, the FastAPI backend allows all origins (*). For public deployments, explicitly whitelist your domain to prevent cross-origin attacks:
CORS_ORIGINS=https://notebook.example.com,https://admin.example.com
This prevents malicious sites from issuing authenticated requests using stolen session tokens, as implemented in the API configuration.
Add Hardening HTTP Headers
Inject security headers at the reverse proxy to mitigate clickjacking, MIME sniffing, and XSS attacks:
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";
These headers ensure browsers handle the content securely and enforce HTTPS connections for all subdomains.
Advanced Enterprise Controls
For deployments requiring more than basic password protection, consider these additional layers:
- SSO / OAuth2: Deploy an OAuth2 proxy (e.g.,
oauth2-proxy) in front of Open Notebook and forward tokens via theAuthorizationheader. - Role-Based Access: Implement custom FastAPI middleware that reads JWT roles from
open_notebook/…and enforces per-endpoint permissions. - Rate Limiting: Add
limit_reqin Nginx or use Traefik's rate-limit middleware to prevent brute-force attacks. - Audit Logging: Pipe container logs to a centralized shipper (Loki, Elastic) to track authentication attempts and data access.
- At-Rest Encryption: Store
notebook_dataon an encrypted volume (LUKS or Docker volume driver) to protect against host compromise.
These recommendations are compiled in the Enterprise Considerations section of docs/5-CONFIGURATION/security.md.
Operational Practices
Maintain security through continuous monitoring and hygiene:
- Regular Updates: Keep the Open Notebook image, SurrealDB, and reverse-proxy software patched to latest stable versions.
- Backup Strategy: Encrypt backups of both the database and the encryption key separately; loss of the key makes API keys unrecoverable.
- Log Monitoring: Review
docker logs open-notebookand proxy access logs for unauthorized authentication attempts. - Pre-Deployment Testing: Verify that
curl https://your-domain.com/healthreturns JSON without authentication, whilecurl https://your-domain.com/api/configrejects requests missing theAuthorizationheader. - HTTPS Enforcement: Ensure TLS termination happens at the proxy so passwords and API keys never traverse the network in plaintext.
Sample Production Docker Compose
services:
surrealdb:
image: surrealdb/surrealdb:v2
command: start --log info --user root --pass root rocksdb:/mydata/mydatabase.db
ports: ["8000:8000"]
volumes: ["./surreal_data:/mydata"]
restart: always
open-notebook:
image: lfnovo/open_notebook:v1-latest
environment:
- OPEN_NOTEBOOK_ENCRYPTION_KEY=${OPEN_NOTEBOOK_ENCRYPTION_KEY}
- OPEN_NOTEBOOK_PASSWORD=${OPEN_NOTEBOOK_PASSWORD}
- CORS_ORIGINS=https://notebook.example.com
- API_URL=https://notebook.example.com
ports:
- "127.0.0.1:8502:8502"
volumes: ["./notebook_data:/app/data"]
depends_on: [surrealdb]
restart: always
nginx:
image: nginx:alpine
ports: ["80:80","443:443"]
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on: [open-notebook]
restart: always
This configuration binds the application to localhost, separates the database, and prepares for TLS termination at the reverse proxy.
Summary
- Store secrets safely using Docker secrets or encrypted env files for
OPEN_NOTEBOOK_ENCRYPTION_KEYandOPEN_NOTEBOOK_PASSWORD. - Expose only port 8502 via localhost binding and route all traffic through a reverse proxy with valid TLS certificates.
- Block port 5055 publicly and restrict database access to the application container only.
- Set explicit CORS origins instead of allowing wildcard access.
- Inject security headers (HSTS, X-Frame-Options) at the proxy layer.
- Monitor logs and maintain regular encrypted backups of both data and encryption keys.
Frequently Asked Questions
Is Open Notebook secure for public deployment by default?
Open Notebook provides a solid privacy-first foundation with Fernet encryption for API keys and password-based authentication, but it requires explicit hardening for public exposure. According to docs/SECURITY_REVIEW.md, you must configure reverse proxies, CORS restrictions, and network isolation to achieve production-grade security.
How do I rotate the encryption key without losing data?
You cannot rotate the OPEN_NOTEBOOK_ENCRYPTION_KEY without re-encrypting all stored credentials. The key is SHA-256-derived and used to encrypt provider API keys in open_notebook/ai/…. To rotate safely, decrypt all credentials using the old key, update the environment variable, and re-save each API key through the application interface to re-encrypt with the new key.
Should I expose the FastAPI backend directly?
No. The FastAPI service on port 5055 should remain inaccessible from the public Internet. The Next.js frontend routes /api/* requests internally to the backend. Exposing port 5055 directly bypasses the reverse proxy's security headers and TLS termination, violating the architecture described in docs/5-CONFIGURATION/reverse-proxy.md.
What is the recommended way to handle database credentials?
Store SurrealDB credentials as Docker secrets or environment variables excluded from version control. The database container should reside on an internal Docker network with no published ports, accessible only to the Open Notebook application container. This network segmentation prevents direct database access even if the application layer is compromised.
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 →