# Docker Deployment Guide ## Quick Start (Local / Self-Hosted) ```bash # 1. Configure cp .env.example .env # Edit .env with your API keys # 2. Generate config (for Cloud Run builds) cp config/config.example.json config/config.json # Edit config/config.json with your brand/model settings node scripts/generate-config.js # 3. Start docker compose up -d ``` Open http://localhost:3000 ## Architecture ``` ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Chat UI │────▶│ MCP Bridge │────▶│ MongoDB │ │ :3000 │ │ :3001 │ │ :27017 │ │ │ │ │ │ │ │ SvelteKit │ │ Express.js │ │ mongo:7 │ │ HF Chat UI │ │ Proxy + MCP │ │ Persistence │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ ├──▶ OpenAI API │ ├──▶ Google Gemini API │ └──▶ OpenRouter API │ └── OPENAI_BASE_URL=http://mcp-bridge:3001 ``` All model requests from Chat UI go through the MCP Bridge, which: 1. Resolves the correct upstream provider from the model name 2. Injects the server-side API key (never exposed to the client) 3. Proxies the OpenAI-compatible request to the upstream provider ## Services ### MongoDB (`mongodb`) - Image: `mongo:7` - Port: 27017 - Volume: `mongo-data` (persistent) - Stores: conversations, user sessions, settings ### MCP Bridge (`mcp-bridge`) - Build: `./mcp-bridge/Dockerfile` - Port: 3001 - Healthcheck: `/health` - Provides: - `/chat/completions` — OpenAI-compatible proxy (routes to Gemini/OpenAI/OpenRouter) - `/mcp` — MCP JSON-RPC endpoint for tool calls - `/health` — Health check ### Chat UI (`chat-ui`) - Build: `./chat-ui/Dockerfile` (extends `ghcr.io/huggingface/chat-ui-db:latest`) - Port: 3000 - Depends on: mongodb, mcp-bridge - Config baked in via `dotenv-local.txt` → `.env.local` ## Environment Variables ### Required (at least one AI provider key) | Variable | Description | |----------|-------------| | `GOOGLE_API_KEY` | Google Gemini API key | | `OPENAI_API_KEY` | OpenAI API key | | `OPENROUTER_API_KEY` | OpenRouter API key | ### Optional — Branding | Variable | Default | Description | |----------|---------|-------------| | `BRAND_NAME` | AI Assistant | App title | | `BRAND_DESCRIPTION` | AI-powered assistant | App subtitle | | `PUBLIC_ORIGIN` | http://localhost:3000 | Public URL | | `MONGODB_DB_NAME` | chat-db | MongoDB database name | ### Optional — Authentication (OIDC) | Variable | Description | |----------|-------------| | `OPENID_PROVIDER_URL` | e.g., `https://accounts.google.com` | | `OPENID_CLIENT_ID` | OAuth client ID | | `OPENID_CLIENT_SECRET` | OAuth client secret | | `OPENID_SCOPES` | Default: `openid profile email` | | `OPENID_NAME_CLAIM` | Default: `name` | | `COOKIE_SECURE` | `true` for HTTPS | | `COOKIE_SAMESITE` | Default: `lax` | ### Optional — Backend Services | Variable | Description | |----------|-------------| | `SEARCH_API_URL` | Your search/knowledge base endpoint | | `RESEARCH_API_URL` | Your research/grounding endpoint | ## Common Operations ```bash # Start all services docker compose up -d # View logs docker compose logs -f docker compose logs -f mcp-bridge # specific service # Restart after .env changes docker compose up -d --force-recreate # Rebuild after code changes docker compose build --no-cache docker compose up -d # Stop docker compose down # Stop and remove data docker compose down -v ``` ## Adding Models Edit `config/config.example.json` → `models` array: ```json { "name": "gemini-2.5-pro", "displayName": "Gemini 2.5 Pro", "description": "Google's most capable model", "provider": "gemini", "supportsTools": true } ``` Provider is resolved from the model name prefix: - `gemini-*` → Google Generative Language API - `gpt-*` → OpenAI API - Everything else → OpenRouter API Then regenerate and rebuild: ```bash node scripts/generate-config.js docker compose build chat-ui docker compose up -d ``` ## Adding MCP Tools Edit `mcp-bridge/index.js`: 1. Add your tool to the `tools` array 2. Add a handler in the `tools/call` switch 3. Rebuild: `docker compose build mcp-bridge && docker compose up -d` ## Production (HTTPS + Domain) For production, put a reverse proxy (nginx, Caddy, Traefik) in front: ```yaml # Add to docker-compose.yml services: caddy: image: caddy:2 ports: - "80:80" - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile - caddy-data:/data depends_on: - chat-ui volumes: caddy-data: ``` ``` # Caddyfile yourdomain.com { reverse_proxy chat-ui:3000 } ``` Set `PUBLIC_ORIGIN=https://yourdomain.com` and `COOKIE_SECURE=true` in `.env`.