services: odysseus: build: ./repo ports: - "${APP_BIND:-0.0.0.0}:${APP_PORT:-3004}:7000" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ${APP_DATA_DIR:-/data/docker/odysseus/data}:/app/data:z - ${APP_LOGS_DIR:-/data/docker/odysseus/logs}:/app/logs:z - ${APP_DATA_DIR:-/data/docker/odysseus/data}/ssh:/app/.ssh:z - ${APP_DATA_DIR:-/data/docker/odysseus/data}/huggingface:/app/.cache/huggingface:z - ${APP_DATA_DIR:-/data/docker/odysseus/data}/local:/app/.local:z - /etc/localtime:/etc/localtime:ro extra_hosts: - "host.docker.internal:host-gateway" environment: - TZ=Europe/Tallinn - LLM_HOST=${LLM_HOST:-localhost} - LLM_HOSTS=${LLM_HOSTS:-http://host.docker.internal:11434,http://host.docker.internal:8070} - OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-http://host.docker.internal:11434} - EMBEDDING_URL=${EMBEDDING_URL:-http://host.docker.internal:11434/v1/embeddings} - EMBEDDING_MODEL=${EMBEDDING_MODEL:-nomic-embed-text} - 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} - FASTEMBED_MODEL=${FASTEMBED_MODEL:-sentence-transformers/all-MiniLM-L6-v2} - CLEANUP_INTERVAL_HOURS=${CLEANUP_INTERVAL_HOURS:-24} - BACKGROUND_TASK_FOREGROUND_GATE=false - ODYSSEUS_ENABLE_HOST_DOCKER=true - ODYSSEUS_CHAT_UPLOAD_MAX_BYTES=${ODYSSEUS_CHAT_UPLOAD_MAX_BYTES:-10485760} - ODYSSEUS_GALLERY_UPLOAD_MAX_BYTES=${ODYSSEUS_GALLERY_UPLOAD_MAX_BYTES:-104857600} - PUID=${PUID:-1000} - PGID=${PGID:-1000} devices: - /dev/kfd - /dev/dri group_add: - video - "122" # docker group - ${RENDER_GID:-render} depends_on: searxng: condition: service_healthy chromadb: condition: service_started networks: - main_ai_network restart: unless-stopped chromadb: image: docker.io/chromadb/chroma:latest ports: - "127.0.0.1:8100:8000" volumes: - chromadb-data:/chroma/chroma environment: - ANONYMIZED_TELEMETRY=FALSE networks: - main_ai_network 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:8088:8080" volumes: - searxng-data:/etc/searxng - ./repo/config/searxng/settings.yml:/tmp/searxng-settings.yml.template:ro,z environment: - SEARXNG_BASE_URL=http://localhost:8080/ 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 networks: - main_ai_network restart: unless-stopped ntfy: image: docker.io/binwiederhier/ntfy command: serve ports: - "127.0.0.1:8091:80" volumes: - ntfy-cache:/var/cache/ntfy - ./ntfy/server.yml:/etc/ntfy/server.yml:ro - ./ntfy/data:/var/lib/ntfy environment: - NTFY_BASE_URL=https://ohmu.tail20e23.ts.net:8091 networks: - main_ai_network restart: unless-stopped volumes: searxng-data: chromadb-data: ntfy-cache: networks: main_ai_network: external: true name: main_ai_network