5 Steps: Zero to Production

Every deployment method in one place — Docker, nginx + TLS, Ollama, cloud APIs, multi-user setup. No scattered docs. No forum hunting. Every config copy-paste ready.

What You'll Build

By the end of this guide, you'll have Open Notebook running behind nginx with TLS, persistent backups, and multi-user access — ready for a small team.

1 Docker Quick Start

Two minutes to a running instance. This gets the app + database up. AI models come in Step 2.

mkdir open-notebook && cd open-notebook
curl -o docker-compose.yml https://raw.githubusercontent.com/lfnovo/open-notebook/main/docker-compose.yml
sed -i 's/change-me-to-a-secret-string/YOUR-ENCRYPTION-KEY/' docker-compose.yml
docker compose up -d
docker compose ps

Wait 15–20 seconds for SurrealDB to initialize. Open http://localhost:8502 — you should see the Open Notebook UI.

Docker not installed? curl -fsSL https://get.docker.com | sh on Linux. For Windows/macOS, install Docker Desktop. This guide assumes Docker Engine 24+ and Compose v2.

What just happened: docker compose up -d started two containers — the Open Notebook app (port 8502 GUI, 5055 API) and SurrealDB (port 8000). Data is stored in Docker volumes, not inside the container filesystem.

2 Connect an AI Provider

Open Notebook needs at least one AI provider for chat, embeddings, and TTS. You have two paths:

Option A: Ollama (free, local, private)

Add this to your docker-compose.yml under services::

ollama:
  image: ollama/ollama:latest
  ports:
    - "11434:11434"
  volumes:
    - ./ollama-data:/root/.ollama
  deploy:
    resources:
      reservations:
        devices:
          - driver: nvidia
            count: all
            capabilities: [gpu]
  pull_policy: always

Pull your first model:

docker exec -it open-notebook-ollama-1 ollama pull gpt-oss:20b

In the Open Notebook UI, go to Settings → API Keys → Add Provider → Ollama. Set Base URL to:

http://ollama:11434
Critical: Use http://ollama:11434, NOT http://localhost:11434. Inside a Docker container, localhost points to the container itself, not the Ollama container. This is the #1 deployment gotcha (GitHub #708, Discussions #88).

Option B: Cloud API (no GPU needed)

Get an API key from any supported provider, then paste it in Settings → API Keys. The $5/month VPS works fine with cloud APIs — no GPU required.

Recommended starter combo (full model guide →):

Chat:     OpenAI GPT-4o-mini    (~$0.15/1M input tokens)
Embed:    text-embedding-3-small (~$0.02/1M tokens)
TTS:      ElevenLabs            (~$0.30/1K chars)

3 Reverse Proxy with nginx + TLS

Never expose ports 8502 or 5055 directly to the internet. Put nginx in front with HTTPS.

server {
    listen 80;
    server_name notebook.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name notebook.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/notebook.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/notebook.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8502;
        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_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    location /api/ {
        proxy_pass http://127.0.0.1:5055/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_read_timeout 300s;
    }
}

Get a free TLS certificate with Let's Encrypt:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d notebook.yourdomain.com

Set the environment variable in your docker-compose.yml:

environment:
  - API_URL=https://notebook.yourdomain.com
Pro tip: The /api/ location block maps to port 5055 with a 300s read timeout — podcast generation can take minutes. Without this timeout, nginx will return 504 errors on long audio generations.

4 Persistent Storage & Backup

Your data lives in two directories — not inside containers. docker compose down won't touch them.

./surreal-data/   →  SurrealDB (notebooks, notes, metadata)
./app-data/       →  Uploaded files, processed documents

Backup script — run this before upgrades or on a cron:

#!/bin/bash
BACKUP_DIR="/backups/open-notebook/$(date +%Y-%m-%d)"
mkdir -p "$BACKUP_DIR"
docker compose stop
tar -czf "$BACKUP_DIR/surreal-data.tar.gz" ./surreal-data/
tar -czf "$BACKUP_DIR/app-data.tar.gz" ./app-data/
docker compose up -d
echo "Backup complete: $BACKUP_DIR"

To restore: stop the containers, extract the tarballs back to the same directories, then docker compose up -d.

Upgrades are safe: docker compose pull && docker compose up -d pulls new images without touching your volumes. Always take a backup before major version bumps.

5 Multi-User Setup

Open Notebook doesn't have built-in multi-tenancy yet, but you can secure it for a small team:

Instance-level password

Set in docker-compose.yml environment:

OPEN_NOTEBOOK_PASSWORD=your-shared-password

nginx basic auth per user

sudo htpasswd -c /etc/nginx/.htpasswd user1
sudo htpasswd /etc/nginx/.htpasswd user2

Add to your nginx config:

location / {
    auth_basic "Open Notebook";
    auth_basic_user_file /etc/nginx/.htpasswd;
    proxy_pass http://127.0.0.1:8502;
    # ... rest of proxy settings
}

Stronger isolation (recommended for teams)

For production team use, run separate docker-compose stacks per team — each with its own SurrealDB instance and data directory. This prevents cross-team data leakage entirely.

Firewall reminder: Always bind to 127.0.0.1. Never expose ports 8502 or 5055 to 0.0.0.0. Use sudo ufw allow 443/tcp && sudo ufw allow 80/tcp && sudo ufw enable to only open nginx ports.

FAQ: Deployment Troubleshooting

localhost:8502 works but Ollama embeddings fail with "Connection error"

This is a known bug (GitHub #655): the Esperanto embedding library ignores the base_url setting for Ollama. The connection test passes but actual embeddings fail. Fix: ensure your Ollama URL in Settings is exactly http://ollama:11434 (Docker service name, not localhost), and the embedding model is pulled in Ollama with ollama pull nomic-embed-text.

Ollama runs out of memory (OOM) on my GPU

Open Notebook v1.8+ defaults num_ctx to 8192 (down from 128000) specifically to prevent this. If you manually raised it, lower it back. Rule of thumb: 1 GB VRAM per ~2048 context tokens at 7B parameters. A 20B model with 8192 ctx needs ~12 GB VRAM. If you have 8 GB, stick to 7B models or reduce context to 4096.

SurrealDB "Permission denied" on Linux

The SurrealDB container runs as root by default. If you're mounting a local directory for ./surreal-data/, ensure it's writable: sudo chown -R 1000:1000 ./surreal-data/. Or add user: root to the SurrealDB service in docker-compose.yml.

Can I run this without Docker?

Not recommended. Open Notebook depends on SurrealDB, which is tightly coupled in the docker-compose setup. Manual install requires: Python 3.11+, SurrealDB binary, pdm for dependency management, and manual config of all environment variables. The Docker path is the supported path — the repo's README and all community guides assume Docker.

Ready for Production?

This guide gets you running. The Production Manual keeps you running — full deploy configs, 30+ error fixes, monitoring, CI/CD, validated against real environments.

Get the Production Manual — $19