# Minimal self-hosted deployment (internal use: no TLS / reverse proxy). # # Flows are the bind-mounted ./backend/flows directory (source of truth); # the embedded API watcher reconciles them into the DB + LFX automatically. # Registry images (:latest) auto-update nightly via watchtower; locally # built images (app, lfx, frontend) update via `docker compose build --pull`. # # Usage: docker compose -f compose.prod.yml up -d --build services: app: build: context: ./backend dockerfile: Dockerfile env_file: - .env environment: DATABASE_URL: sqlite:////srv/backend/data/kirche.db FLOWS_DIR: /srv/backend/flows LFX_URL: http://lfx:6004 LANGFLOW_URL: http://langflow:7860 CALLBACK_BASE_URL: http://app:8000 volumes: - ./backend/flows:/srv/backend/flows - appdata:/srv/backend/data ports: - "8000:8000" depends_on: lfx: condition: service_healthy langflow: condition: service_healthy restart: unless-stopped healthcheck: test: [ "CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://localhost:8000/health', timeout=5)\"", ] interval: 30s timeout: 5s retries: 3 start_period: 30s frontend: build: context: ./frontend dockerfile: Dockerfile ports: - "3000:3000" depends_on: app: condition: service_healthy restart: unless-stopped langflow: image: langflowai/langflow:latest env_file: - .env environment: LANGFLOW_CONFIG_DIR: /app/langflow LANGFLOW_HOST: 0.0.0.0 PORT: "7860" LANGFLOW_AUTO_LOGIN: "false" LANGFLOW_API_KEY_SOURCE: env LANGFLOW_DATABASE_URL: sqlite:////app/langflow/langflow.db volumes: - langflow-data:/app/langflow ports: - "7860:7860" labels: com.centurylinklabs.watchtower.enable: "true" restart: unless-stopped healthcheck: test: [ "CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://localhost:7860/health', timeout=5)\"", ] interval: 30s timeout: 5s retries: 20 start_period: 60s lfx: build: context: .devcontainer dockerfile: Dockerfile.lfx env_file: - .env volumes: - lfx-data:/flows ports: - "6004:6004" restart: unless-stopped healthcheck: test: [ "CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://localhost:6004/health', timeout=5)\"", ] interval: 30s timeout: 5s retries: 12 start_period: 30s watchtower: image: nickfedor/watchtower:latest volumes: - /var/run/docker.sock:/var/run/docker.sock environment: WATCHTOWER_LABEL_ENABLE: "true" WATCHTOWER_SCHEDULE: "0 0 4 * * *" WATCHTOWER_CLEANUP: "true" WATCHTOWER_ROLLING_RESTART: "true" labels: com.centurylinklabs.watchtower.enable: "true" restart: unless-stopped volumes: appdata: langflow-data: lfx-data: