Deploy Odysseus on Render in one click. Get a self-hosted AI workspace — chat, agents, deep research, documents, email, notes, and calendar — running on your own instance with your own API keys.
odysseus.mp4
This Blueprint provisions three services on Render:
| Service | What it is |
|---|---|
odysseus |
The web app (chat, agents, research, documents, email, notes, calendar). Persistent disk at /app/data. |
odysseus-searxng |
Bundled SearXNG for private web search — powers Deep Research with no extra key. |
odysseus-chromadb |
Bundled ChromaDB vector store for RAG and semantic memory. |
Auth is on by default (AUTH_ENABLED=true, secure cookies, a generated admin password), and both helper services are private — only the web app is exposed.
Only odysseus is public. It reaches the two helper services over Render's private network, and calls out to your LLM and (optional) search providers with your own API keys.
┌─────────────────────────────┐
Internet ───► │ odysseus (public web app) │
│ disk: /app/data │
└──────┬───────────────┬──────┘
│ private │ private
┌──────▼──────┐ ┌─────▼────────────┐
│ searxng │ │ chromadb │
│ web search │ │ vector store │
└──────┬──────┘ └──────────────────┘
│
┌─────────┴──────────────────────────────┐
│ external APIs (your keys) │
│ OpenAI · Brave · Tavily · Serper · … │
└────────────────────────────────────────┘
This is the hosted build. Local-model serving (Cookbook/vLLM/llama.cpp), GPU inference, image upscaling, and host-Docker features from the upstream project don't run on Render and are omitted here; Odysseus uses cloud LLM APIs instead. For the full self-hosted feature set, see the upstream repo.
- Click Deploy to Render above.
- Fill in the API keys you want (see below) in the deploy form, then apply the Blueprint.
- Wait for all three services to go live.
Set these as secrets in the deploy form. All are optional per feature — you only need the keys for the features you'll use.
To restrict OPENAI_API_KEY, a key with only the Chat completions (/v1/chat/completions) permission is enough — embeddings run locally (fastembed) and no other OpenAI endpoint is used. Set everything else to None.
| Variable | Needed for | Where to get it |
|---|---|---|
OPENAI_API_KEY |
Chat, agents, research (LLM calls) | platform.openai.com |
OPENAI_DEFAULT_MODEL |
Model seeded as the default chat on first boot (default gpt-5.6-sol; change here or in the app) — not a secret |
— |
DATA_BRAVE_API_KEY |
Brave web search (optional — SearXNG is bundled) | brave.com/search/api |
TAVILY_API_KEY |
Tavily search provider (optional) | tavily.com |
SERPER_API_KEY |
Serper search provider (optional) | serper.dev |
GOOGLE_API_KEY + GOOGLE_PSE_CX |
Google Programmable Search (optional) | Google Cloud |
HF_TOKEN |
Gated Hugging Face models (optional) | huggingface.co/settings/tokens |
Set automatically — no action needed: ODYSSEUS_ADMIN_PASSWORD (generated), SEARXNG_SECRET (generated), plus the internal service wiring.
Advanced — ALLOWED_ORIGINS (CORS): by default the app locks CORS to its own Render URL (it reads RENDER_EXTERNAL_URL automatically), so you don't need to set anything. Only set ALLOWED_ORIGINS if you serve the app from a custom domain or need to allow additional origins — provide a comma-separated list of the full origins (e.g. https://app.example.com,https://www.example.com).
- Open the
odysseusservice URL once it's live. - Log in as
admin. Your admin password is created for you automatically at deploy time — you don't set one. Find it in the Render Dashboard → theodysseusservice → Environment →ODYSSEUS_ADMIN_PASSWORD(a strong, randomly generated 256-bit value). Copy it to log in, then change it from the app after first login. It's never printed to the logs. - To have chat work out of the gate, set
OPENAI_API_KEYon theodysseusweb service's env vars before first boot. On startup the deploy seeds an OpenAI endpoint from that key (default modelOPENAI_DEFAULT_MODEL), so you can open Chat, send a message, and get a reply with nothing to wire up in the model picker. - Try Deep Research: click Deep Research in the tools menu on the left-hand side to open its modal, enter your question, and run it. It searches the web through the bundled SearXNG (no extra key) and generates a sourced report.
Want to let strangers try the app without an admin password? See Demo mode below — a public, no-signup chat surface you can turn on with
DEMO=true. It's off by default, so a fresh deploy stays fully authenticated.
DEMO=true runs a public, no-signup, locked-down chat demo on your OpenAI key — so anyone with the URL can try the chat without logging in. It is off by default (DEMO=false): a fresh fork or deploy gets the full authenticated app, unchanged. Only a deliberate DEMO=true turns it on.
How it works. With the flag on, the login gate opens for chat only. Each visitor gets an isolated, ephemeral demo session (an unguessable per-visitor cookie → a synthetic owner) under a least-privilege profile. Everything else — settings, admin, integrations, and every other API route — still requires the admin login exactly as before. The admin account and its password are untouched.
What the demo can and can't do:
| Capability | In demo |
|---|---|
| Chat (pinned cheap model, capped output) | ✅ on |
| Shell / code / file tools | ❌ off |
| File upload & personal-doc RAG | ❌ off |
| Image generation, TTS / STT | ❌ off |
| Deep research | ❌ off (expensive per run) |
| Email, MCP servers, cookbook, task scheduler | ❌ off |
| Memory writes, API-token minting | ❌ off |
| Settings / admin / integrations | ❌ off (admin login still required) |
Abuse & cost limits (demo-only; the demo spends your key, so watch your OpenAI usage console):
| Variable | Default | What it caps |
|---|---|---|
DEMO_MODEL |
gpt-5.6-luna |
the pinned (cheap) chat model |
DEMO_MAX_OUTPUT_TOKENS |
512 |
output tokens per reply |
DEMO_RATE_LIMIT_PER_MINUTE |
10 |
chat sends per minute, per client IP |
DEMO_MAX_MESSAGES_PER_SESSION |
30 |
total messages per visitor cookie session (UX friction) |
DEMO_MAX_MESSAGES_PER_IP_PER_DAY |
200 |
hard per-IP daily message ceiling (the real backstop) |
Raise or lower these in the deploy form / render.yaml. Set a limit to 0 to disable that one dimension; an unset variable falls back to the default (it never means "unlimited"). When a visitor hits a cap they get a friendly "deploy your own to keep going" reply — never an error.
The rate limit and the per-IP daily ceiling are keyed on the trusted client IP — the entry Render's proxy attests on X-Forwarded-For, read from the right (TRUSTED_PROXY_HOPS hops in, default 1), never the spoofable leftmost value. So clearing cookies or churning the demo session can't reset them. The per-session cap is cookie-based, so it's UX friction only; the per-IP ceiling is the volume backstop. Visitors behind one NAT/IP share a bucket — that errs toward more limiting, which is what you want for a cost guard.
TRUSTED_PROXY_HOPSis app-wide, not demo-only: the auth login/signup/setup rate limiters key on the same trusted IP. On first traffic the app logs a one-time[trusted-ip] X-Forwarded-For sampleline — check it once on your deploy to confirm1hop resolves your real client IP (retune if you front the service with extra proxies).Deploying off Render? Set
TRUSTED_PROXY_HOPSto match your topology:0if the service is directly internet-facing with no proxy in front (the wholeX-Forwarded-Forheader is then attacker-supplied, so it's ignored and the limiters key on the real TCP peer), orNforNtrusted proxies. Leaving the default1on a proxy-less deploy lets a client spoofX-Forwarded-Forand bypass every IP-keyed limit.
Your real spend ceiling is the OpenAI limit, not these counters. The caps above bound the burn rate; they reduce how fast the key can be spent, they don't cap total dollars. The one true per-call ceiling is
DEMO_MAX_OUTPUT_TOKENS. For a hard dollar cap, set a monthly usage limit on your OpenAI project — that's what protects the bill if the demo URL is discovered or abused.
Session isolation & privacy. Visitors can't see each other's chats (each is scoped to its own synthetic owner), and demo history is ephemeral — it lives in memory only and is never written to the deployer's disk. If you host a public demo URL, add a visible "public demo, may reset — don't submit anything sensitive" notice.
The Blueprint defaults the web service to standard (2 GB). Odysseus can be resource-hungry under heavy use — large deep-research runs, big documents, sizable embedding jobs, or many concurrent sessions. For those workloads, give the instance more resources: in the Render Dashboard, open the odysseus service → Settings → Instance Type and pick a larger plan (and bump odysseus-chromadb too if your vector store grows). You can downgrade later if the smaller plan proves sufficient.
Full documentation, the complete self-hosted feature set, and contributing guidelines live in the upstream project: odysseus-dev/odysseus.
AGPL-3.0-or-later — see LICENSE and ACKNOWLEDGMENTS.md.

