Deploying the Docs Site
Production deployment of nibiru-framework.com using jwilder/nginx-proxy and your own Ollama on your Ollama instance.
This page documents how the docs site is deployed in production. The setup uses jwilder/nginx-proxy for automatic Docker container routing, letsencrypt-nginx-proxy-companion for HTTPS, and your own Ollama at your-ollama-host.example for the Oracle backend — no paid LLM API keys required.
Topology
Section titled “Topology” Internet │ ▼ ┌──────────────────────┐ │ jwilder/nginx-proxy │ ← reverse proxy on :80 / :443 │ (network: nginx-proxy)│ terminates TLS └──────────┬───────────┘ │ http://nibiru-docs:4321 ▼ ┌──────────────────────┐ ┌──────────────────────┐ │ nibiru-docs │ ──────▶ │ your-ollama-host.example │ │ Astro Node SSR :4321 │ HTTPS │ Ollama (5× GPU) │ │ Oracle endpoint │ │ qwen2.5-coder:14b │ └──────────────────────┘ │ nomic-embed-text │ └──────────────────────┘Prerequisites on the host
Section titled “Prerequisites on the host”# 1) Create the shared external network (one time)docker network create nginx-proxy
# 2) Run nginx-proxy + acme-companion (one time)# See https://github.com/nginx-proxy/nginx-proxy for the canonical compose.
# 3) Pull the Oracle's models on your Ollama instance (one time)curl https://your-ollama-host.example/api/pull -d '{"name":"qwen2.5-coder:14b"}'curl https://your-ollama-host.example/api/pull -d '{"name":"nomic-embed-text"}'Files in docs/
Section titled “Files in docs/”| File | Purpose |
|---|---|
Dockerfile | Multi-stage build: builds Oracle index against your Ollama instance, builds Astro, prunes dev deps. |
docker-compose.yml | Production — VIRTUAL_HOST=nibiru-framework.com, joined to nginx-proxy network. |
docker-compose.local.yml | Local-test override — exposes 4321:4321, drops nginx-proxy env vars. |
.dockerignore | Keeps node_modules, .git, etc. out of the build context. |
.env.example | Template — defaults to Ollama on your Ollama instance, no API keys required. |
Bring it up
Section titled “Bring it up”cd docscp .env.example .env# defaults are fine for production unless you want to override the Ollama URL or models
docker compose up -d --buildThe first build runs build-oracle-index.mjs to embed the docs against your Ollama. Subsequent rebuilds are fast — Docker caches the dep layer; only changed chunks need re-embedding.
After ~30 seconds, jwilder/nginx-proxy picks up the new container, requests a Let’s Encrypt cert, and routes https://nibiru-framework.com → :4321.
Verify
Section titled “Verify”curl -s https://nibiru-framework.com/api/oracle | jq# {# "status": "ok",# "llm": { "provider": "ollama", "model": "qwen2.5-coder:14b", … },# "embed": { "provider": "ollama", "model": "nomic-embed-text", … },# "index": { "present": true, "chunks": 177, … }# }Or open the site in a browser, click the amber Oracle launcher, and ask a question.
Update after a docs change
Section titled “Update after a docs change”git pulldocker compose up -d --buildThe build re-runs the Oracle index against the freshest content; the new container starts on :4321; jwilder swaps the upstream; the old container is stopped — no noticeable downtime.
Environment variables
Section titled “Environment variables”| Var | Default | Used at | Purpose |
|---|---|---|---|
LLM_PROVIDER | ollama | runtime | ollama (default) or anthropic. |
OLLAMA_BASE_URL | https://your-ollama-host.example | build + runtime | Where to reach Ollama. |
OLLAMA_CHAT_MODEL | qwen2.5-coder:14b | runtime | Chat-completion model. |
OLLAMA_EMBED_MODEL | nomic-embed-text | build + runtime | Embedding model. |
EMBED_PROVIDER | ollama | build + runtime | ollama or openai. |
ANTHROPIC_API_KEY | — | runtime | Only used if LLM_PROVIDER=anthropic. |
ANTHROPIC_MODEL | claude-haiku-4-5-20251001 | runtime | Override Claude model. |
OPENAI_API_KEY | — | build + runtime | Only used if EMBED_PROVIDER=openai. |
ORACLE_TOP_K | 6 | runtime | Chunks injected per Oracle response. |
LETSENCRYPT_EMAIL | stephan.kasdorf@bittomine.com | letsencrypt | Where Let’s Encrypt sends expiry notices. |
VIRTUAL_HOST | nibiru-framework.com,www.nibiru-framework.com | nginx-proxy | Set in compose. |
Troubleshooting
Section titled “Troubleshooting”502 Bad Gateway. The upstream container failed to start. Check
docker logs nibiru-docs — likely missing build artifact in dist/server/entry.mjs.
Cert not issued. Let’s Encrypt rate-limits aggressively. Check
docker logs letsencrypt-nginx-proxy-companion for the cause.
Oracle answers without citations. The embedding index is empty. Either
nomic-embed-text isn’t pulled on Ollama, or the build couldn’t reach
your Ollama instance. Re-pull the model:
curl https://your-ollama-host.example/api/pull -d '{"name":"nomic-embed-text"}'docker compose up -d --buildOracle returns “the Oracle could not answer”. Check the chat model is pulled:
curl https://your-ollama-host.example/api/tags | jq '.models[].name'Want to fall back to Claude. Set LLM_PROVIDER=anthropic and ANTHROPIC_API_KEY in .env, then docker compose up -d.
Resource usage
Section titled “Resource usage”| Idle | Under Oracle load | |
|---|---|---|
| RAM | ~120 MB | ~200 MB |
| CPU | < 0.5% | ~5% |
| Network | minimal | one HTTPS round-trip per question |
| Disk | ~60 MB image + ~5 MB index | + corpus exports |
A 1 GB / 1 vCPU droplet handles the docs site comfortably alongside other services. The heavy lifting (LLM inference) happens on your GPU cluster, not the docs container.