From 0ad99b6199e8694ef9a326acb6bbc9e7e508eb54 Mon Sep 17 00:00:00 2001 From: William Gill Date: Sun, 19 Apr 2026 11:57:24 -0500 Subject: [PATCH] Add comfyui-model-init sidecar for ComfyUI model preseeding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the Ollama model-init pattern: a one-shot Alpine container that mounts the comfyui-models volume and runs comfyui-init-models.sh, which curls direct download URLs (HuggingFace by default) into the right subdirectories. Idempotent — already-present files are skipped. HF_TOKEN is plumbed through for gated repos (Flux-dev, SD3, etc.) and is opt-in via .env. The default list ships SD 1.5 only, matching the placeholder filename in workflows/*.json. Examples for SDXL, Flux, and upscalers are commented in the script. Co-Authored-By: Claude Opus 4.7 (1M context) --- deployments/ai-stack/.env.example | 5 ++ deployments/ai-stack/README.md | 47 +++++++++------ deployments/ai-stack/comfyui-init-models.sh | 65 +++++++++++++++++++++ deployments/ai-stack/docker-compose.yml | 17 ++++++ 4 files changed, 115 insertions(+), 19 deletions(-) create mode 100644 deployments/ai-stack/comfyui-init-models.sh diff --git a/deployments/ai-stack/.env.example b/deployments/ai-stack/.env.example index 54b8f28..d81ae83 100644 --- a/deployments/ai-stack/.env.example +++ b/deployments/ai-stack/.env.example @@ -22,3 +22,8 @@ ANUBIS_OWUI_KEY=replace-with-32-byte-hex # ComfyUI image tag to deploy. `latest` tracks whatever the release workflow # last pushed; pin to a v* tag (e.g. 0.1.0) for reproducible deploys. COMFYUI_IMAGE_TAG=latest + +# HuggingFace access token. Only needed if comfyui-init-models.sh references +# gated repos (Flux-dev, SD3, etc.). Generate a read token at +# https://huggingface.co/settings/tokens. Leave empty for public-only. +HF_TOKEN= diff --git a/deployments/ai-stack/README.md b/deployments/ai-stack/README.md index 73a69bd..36760f3 100644 --- a/deployments/ai-stack/README.md +++ b/deployments/ai-stack/README.md @@ -10,12 +10,13 @@ production `srvno.de` deployment. ## Files -| File | Purpose | -| ------------------- | -------------------------------------------------------- | -| `docker-compose.yml`| Service definitions, volumes, GPU reservations | -| `Caddyfile` | TLS + reverse proxy config (one site block per hostname) | -| `init-models.sh` | Models to preseed into Ollama on first boot | -| `.env.example` | Secrets and image-tag pins. Copy to `.env` | +| File | Purpose | +| -------------------------- | -------------------------------------------------------- | +| `docker-compose.yml` | Service definitions, volumes, GPU reservations | +| `Caddyfile` | TLS + reverse proxy config (one site block per hostname) | +| `init-models.sh` | LLMs to preseed into Ollama on first boot | +| `comfyui-init-models.sh` | Checkpoints/VAEs/LoRAs to preseed into ComfyUI on first boot | +| `.env.example` | Secrets and image-tag pins. Copy to `.env` | ## 1. Host prerequisites @@ -61,6 +62,10 @@ Then edit: - **`init-models.sh`** — keep the LLMs you want preseeded, drop the rest. Check sizes at first; the host needs disk for everything listed. +- **`comfyui-init-models.sh`** — checkpoints/VAEs/LoRAs to preseed into + ComfyUI. Default ships SD 1.5 only (matches the workflow placeholder). + Uncomment the SDXL/Flux/upscaler examples or add your own. Set `HF_TOKEN` + in `.env` if any are gated repos. ## 3. Bring it up @@ -80,22 +85,26 @@ docker compose exec comfyui curl -sf http://127.0.0.1:8188/system_stats | head - docker compose exec open-webui curl -sf http://127.0.0.1:8080/health ``` -## 4. Drop in at least one ComfyUI checkpoint +## 4. ComfyUI checkpoints -ComfyUI ships no models. The shipped workflow templates reference -`v1-5-pruned-emaonly.safetensors` as a placeholder; drop any -SD/SDXL/Flux checkpoint into the `comfyui-models` volume under -`checkpoints/`: +ComfyUI ships no models. Three ways to get one in: -```sh -docker run --rm -v ai-stack_comfyui-models:/models -w /models/checkpoints \ - curlimages/curl:latest -L -O \ - https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors -``` +1. **Preseed via the sidecar (default).** `comfyui-model-init` runs once + on `compose up`, downloads everything `comfyui-init-models.sh` lists, + and exits. The default list pulls SD 1.5 to match the workflow + placeholder. Edit the script to add SDXL, Flux, LoRAs, upscalers, etc. + Re-run with `docker compose up -d comfyui-model-init` after edits; + already-present files are skipped. +2. **ComfyUI-Manager UI.** Open `https://comfyui.example.com` (after + basic-auth login), click **Manager**, then **Model Manager**, install + from the catalogue. +3. **Direct copy into the volume.** Useful if you already have the file + locally: -Or open the ComfyUI native UI at `https://comfyui.example.com` (after -basic-auth login), use the **Manager** button (added by ComfyUI-Manager), -and install one through **Model Manager**. + ```sh + docker run --rm -v ai-stack_comfyui-models:/models -v $PWD:/src alpine \ + cp /src/your-model.safetensors /models/checkpoints/ + ``` ## 5. First-user signup in Open WebUI diff --git a/deployments/ai-stack/comfyui-init-models.sh b/deployments/ai-stack/comfyui-init-models.sh new file mode 100644 index 0000000..7b586ac --- /dev/null +++ b/deployments/ai-stack/comfyui-init-models.sh @@ -0,0 +1,65 @@ +#!/bin/sh +# Preseed ComfyUI's models volume with checkpoints, VAEs, LoRAs, etc. +# Runs once via the comfyui-model-init service (see docker-compose.yml). +# Safe to re-run — already-present files are skipped. +# +# ComfyUI doesn't have a "pull" command of its own, so this is plain curl +# against direct download URLs. For HuggingFace, the direct URL is: +# https://huggingface.co//resolve/main/ +# For gated HF repos (Flux-dev, SD3, etc.), set HF_TOKEN in .env — the +# script attaches it as a bearer token automatically. + +set -e + +apk add --no-cache curl >/dev/null + +mkdir -p /models/checkpoints /models/vae /models/loras /models/controlnet \ + /models/clip /models/clip_vision /models/upscale_models /models/embeddings + +fetch() { + dest="$1"; name="$2"; url="$3" + target="/models/$dest/$name" + + if [ -f "$target" ]; then + echo "✓ $dest/$name already present" + return + fi + + echo "→ Downloading $dest/$name…" + mkdir -p "/models/$dest" + + if [ -n "$HF_TOKEN" ] && echo "$url" | grep -q huggingface.co; then + curl -fL -C - --retry 3 -H "Authorization: Bearer $HF_TOKEN" \ + -o "$target.partial" "$url" + else + curl -fL -C - --retry 3 -o "$target.partial" "$url" + fi + mv "$target.partial" "$target" +} + +# ─── Edit the list below to choose what gets preseeded ────────────────────── +# Format: fetch + +# SD 1.5 base — matches the placeholder filename in workflows/*.json +fetch checkpoints v1-5-pruned-emaonly.safetensors \ + https://huggingface.co/stable-diffusion-v1-5/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors + +# Examples — uncomment what you want. + +# SDXL Base 1.0 (~6.9 GB) +# fetch checkpoints sd_xl_base_1.0.safetensors \ +# https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/main/sd_xl_base_1.0.safetensors + +# SDXL VAE (fixes washed-out colours on some SDXL checkpoints) +# fetch vae sdxl_vae.safetensors \ +# https://huggingface.co/stabilityai/sdxl-vae/resolve/main/sdxl_vae.safetensors + +# Flux.1-dev (~23 GB, gated — needs HF_TOKEN with access to black-forest-labs) +# fetch checkpoints flux1-dev.safetensors \ +# https://huggingface.co/black-forest-labs/FLUX.1-dev/resolve/main/flux1-dev.safetensors + +# 4x-UltraSharp upscaler +# fetch upscale_models 4x-UltraSharp.pth \ +# https://huggingface.co/lokCX/4x-Ultrasharp/resolve/main/4x-UltraSharp.pth + +echo "Done." diff --git a/deployments/ai-stack/docker-compose.yml b/deployments/ai-stack/docker-compose.yml index 66c63c3..33c38c9 100644 --- a/deployments/ai-stack/docker-compose.yml +++ b/deployments/ai-stack/docker-compose.yml @@ -129,6 +129,23 @@ services: retries: 5 start_period: 120s + # One-shot model puller for ComfyUI. Mounts the same models volume, + # downloads whatever comfyui-init-models.sh lists, exits. ComfyUI doesn't + # need to be running for this — files just land on the volume; ComfyUI + # picks them up next time it scans (or on a restart). + comfyui-model-init: + image: alpine:latest + container_name: comfyui-model-init + volumes: + - comfyui-models:/models + - ./comfyui-init-models.sh:/init.sh:ro + environment: + # Optional — set in .env to download from gated HuggingFace repos + # (Flux-dev, SD3, etc.). Leave empty for public-only. + HF_TOKEN: "${HF_TOKEN:-}" + entrypoint: ["/bin/sh", "/init.sh"] + restart: "no" + # --------------------------------------------------------------------------- # Open WebUI — multi-user chat. # ---------------------------------------------------------------------------