FROM ghcr.io/berriai/litellm:v1.103.2 # v1.84.0 is the fix line for CVE-2026-35029 (auth bypass on # /config/update, fixed 1.83.0) and CVE-2026-59822 (MCP session auth # bypass, fixed 1.84.0, CISA KEV catalog). Pin the exact tag — do NOT # use a floating tag like main-v1.74.0-stable, which silently moved. # LiteLLM's official image runs as root. Cloudron's sandboxing (read-only # rootfs, AppArmor, dropped capabilities) still applies to root inside the # container, so we keep root to match the base image and avoid /app/data # volume-ownership issues. # Create the data directory (Cloudron mounts the localstorage volume here) RUN mkdir -p /app/data /app/code # Create a startup script that configures LiteLLM with Cloudron addons COPY start.sh /app/code/start.sh RUN chmod +x /app/code/start.sh # Default config — will be overridden by Cloudron env vars at runtime COPY config.yaml /app/data/config.yaml # Append the co-op credit-pack hint to LiteLLM's hardcoded budget-exceeded # messages. Done at BUILD time — the runtime rootfs is read-only under # Cloudron, so a boot-time patch would crash the startup script (it did, # 2026-10-06). patch_budget_message.py is non-fatal: it exits 0 even when the # file/message can't be found, so a future LiteLLM version bump can't take the # gateway down. COPY patch_budget_message.py /app/code/patch_budget_message.py RUN python3 /app/code/patch_budget_message.py # Image-cost tracking: keep image-generation pricing on the shared cost-map # key so successful image generations appear in SpendLogs (upstream bug # BerriAI/litellm#10023/#12471 — closed not-planned). Non-fatal at build. COPY patch_image_cost.py /app/code/patch_image_cost.py RUN python3 /app/code/patch_image_cost.py # Audio keep-alive: scheduled pings keep the Tinfoil TEE audio enclave # warm so voice mode skips the ~24s cold-start (see audio_keepalive.py header). COPY audio_keepalive.py /app/code/audio_keepalive.py RUN chmod +x /app/code/audio_keepalive.py # Override the base image's ENTRYPOINT (which is `litellm`) so our # startup script runs instead of being passed as an argument to litellm. ENTRYPOINT ["/app/code/start.sh"] # No CORS patch needed since v1.84.0: upstream replaced the hardcoded # `origins = ["*"]` with a native LITELLM_CORS_ORIGINS env var (start.sh # exports it). The old sed patch targeted a v1.74.0 file layout that no # longer exists — the v1.84.0 rebuild self-skipped it correctly.