| services:
|
| odysseus:
|
| build: .
|
| ports:
|
| - "${APP_BIND:-127.0.0.1}:${APP_PORT:-7000}:7000"
|
| volumes:
|
| - ./data:/app/data:z
|
| - ./logs:/app/logs:z
|
|
|
|
|
| - ./data/ssh:/app/.ssh:z
|
|
|
|
|
| - ./data/huggingface:/app/.cache/huggingface:z
|
|
|
|
|
|
|
| - ./data/local:/app/.local:z
|
| extra_hosts:
|
|
|
|
|
| - "host.docker.internal:host-gateway"
|
| environment:
|
| - LLM_HOST=${LLM_HOST:-localhost}
|
| - LLM_HOSTS=${LLM_HOSTS:-}
|
| - OPENAI_API_KEY=${OPENAI_API_KEY:-}
|
| - OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-}
|
| - RESEARCH_LLM_ENDPOINT=${RESEARCH_LLM_ENDPOINT:-}
|
| - HF_TOKEN=${HF_TOKEN:-}
|
| - HUGGING_FACE_HUB_TOKEN=${HUGGING_FACE_HUB_TOKEN:-}
|
| - SEARXNG_INSTANCE=http://searxng:8080
|
| - CHROMADB_HOST=chromadb
|
| - CHROMADB_PORT=8000
|
| - DATABASE_URL=${DATABASE_URL:-sqlite:///./data/app.db}
|
| - AUTH_ENABLED=${AUTH_ENABLED:-true}
|
| - LOCALHOST_BYPASS=${LOCALHOST_BYPASS:-false}
|
| - ODYSSEUS_ADMIN_USER=${ODYSSEUS_ADMIN_USER:-admin}
|
| - ODYSSEUS_ADMIN_PASSWORD=${ODYSSEUS_ADMIN_PASSWORD:-}
|
| - ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-http://localhost,http://127.0.0.1}
|
| - SECURE_COOKIES=${SECURE_COOKIES:-false}
|
| - EMBEDDING_URL=${EMBEDDING_URL:-}
|
| - EMBEDDING_MODEL=${EMBEDDING_MODEL:-}
|
| - EMBEDDING_API_KEY=${EMBEDDING_API_KEY:-}
|
| - FASTEMBED_MODEL=${FASTEMBED_MODEL:-sentence-transformers/all-MiniLM-L6-v2}
|
| - FASTEMBED_CACHE_PATH=${FASTEMBED_CACHE_PATH:-}
|
| - CLEANUP_INTERVAL_HOURS=${CLEANUP_INTERVAL_HOURS:-24}
|
| - ODYSSEUS_INPROCESS_POLLERS=${ODYSSEUS_INPROCESS_POLLERS:-1}
|
| - ODYSSEUS_INPROCESS_TASKS=${ODYSSEUS_INPROCESS_TASKS:-1}
|
| - ODYSSEUS_SCRIPT_HOST=${ODYSSEUS_SCRIPT_HOST:-localhost}
|
| - ODYSSEUS_CHAT_UPLOAD_MAX_BYTES=${ODYSSEUS_CHAT_UPLOAD_MAX_BYTES:-10485760}
|
| - DATA_BRAVE_API_KEY=${DATA_BRAVE_API_KEY:-}
|
| - GOOGLE_API_KEY=${GOOGLE_API_KEY:-}
|
| - GOOGLE_PSE_CX=${GOOGLE_PSE_CX:-}
|
| - TAVILY_API_KEY=${TAVILY_API_KEY:-}
|
| - SERPER_API_KEY=${SERPER_API_KEY:-}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| - PUID=${PUID:-1000}
|
| - PGID=${PGID:-1000}
|
| depends_on:
|
| searxng:
|
| condition: service_healthy
|
| chromadb:
|
| condition: service_started
|
| restart: unless-stopped
|
|
|
| chromadb:
|
| image: docker.io/chromadb/chroma:latest
|
| ports:
|
| - "${CHROMADB_BIND:-127.0.0.1}:8100:8000"
|
| volumes:
|
| - chromadb-data:/chroma/chroma
|
| environment:
|
| - ANONYMIZED_TELEMETRY=FALSE
|
| restart: unless-stopped
|
|
|
| searxng:
|
|
|
|
|
|
|
|
|
|
|
| image: docker.io/searxng/searxng:2026.5.31-7159b8aed
|
| entrypoint:
|
| - /bin/sh
|
| - -c
|
| - |
|
| set -eu
|
| if [ ! -s /etc/searxng/settings.yml ] || grep -q 'odysseus-local-searxng-json-2026-05-30\|__SEARXNG_SECRET__' /etc/searxng/settings.yml; then
|
| secret="$${SEARXNG_SECRET:-}"
|
| if [ -z "$$secret" ]; then
|
| secret="$$(python -c 'import secrets; print(secrets.token_urlsafe(48))')"
|
| fi
|
| sed "s|__SEARXNG_SECRET__|$$secret|g" /tmp/searxng-settings.yml.template > /etc/searxng/settings.yml
|
| fi
|
| exec /usr/local/searxng/entrypoint.sh
|
| ports:
|
| - "127.0.0.1:8080:8080"
|
| volumes:
|
| - searxng-data:/etc/searxng
|
| - ./config/searxng/settings.yml:/tmp/searxng-settings.yml.template:ro,z
|
| environment:
|
| - SEARXNG_BASE_URL=http://localhost:8080/
|
| - SEARXNG_SECRET=${SEARXNG_SECRET:-}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| cap_drop:
|
| - ALL
|
| cap_add:
|
| - CHOWN
|
| - SETGID
|
| - SETUID
|
| - DAC_OVERRIDE
|
| healthcheck:
|
| test: ["CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://localhost:8080/', timeout=5).read(1)\""]
|
| interval: 5s
|
| timeout: 6s
|
| retries: 20
|
| start_period: 10s
|
| restart: unless-stopped
|
|
|
| ntfy:
|
| image: docker.io/binwiederhier/ntfy
|
| command: serve
|
| ports:
|
| - "${NTFY_BIND:-127.0.0.1}:8091:80"
|
| volumes:
|
| - ntfy-cache:/var/cache/ntfy
|
| environment:
|
| - NTFY_BASE_URL=${NTFY_BASE_URL:-http://localhost:8091}
|
| restart: unless-stopped
|
|
|
| volumes:
|
| searxng-data:
|
| chromadb-data:
|
| ntfy-cache:
|
|
|