Make ai-stack the only deployment shape

Drops the duplicate standalone compose / .env.example / SETUP.md at the
repo root. Bring-up content folded into deployments/ai-stack/README.md
so there's exactly one set of deployment instructions, sitting next to
the files it describes. Root README is now just the repo overview and a
pointer at the deployment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-19 10:45:23 -05:00
co-authored by Claude Opus 4.7
parent b1c9bff15f
commit 97547c783c
5 changed files with 173 additions and 333 deletions
-9
View File
@@ -1,9 +0,0 @@
# Copy to .env and edit. docker compose picks .env up automatically.
# Public hostname/scheme your reverse proxy terminates. Used by Open WebUI for
# auth redirects and email-link generation.
OPEN_WEBUI_URL=http://localhost:3000
# Cookie-signing key. Generate once with: openssl rand -hex 32
# Must stay stable across restarts — rotating it logs every user out.
OPEN_WEBUI_SECRET_KEY=change-me-please
+22 -39
View File
@@ -1,50 +1,33 @@
# comfyui-nvidia
ComfyUI image-generation backend, NVIDIA-accelerated, fronted by Open WebUI for
multi-user chat and image generation/editing.
ComfyUI image-generation backend, NVIDIA-accelerated, fronted by Open WebUI
for multi-user chat and image generation/editing.
Built from the official ComfyUI [manual install for
NVIDIA](https://docs.comfy.org/installation/manual_install#nvidia) — no third-
party base image. Two services on one bridge network:
NVIDIA](https://docs.comfy.org/installation/manual_install#nvidia) — no
third-party base image. CI publishes the image to
`git.anomalous.dev/alphacentri/comfyui-nvidia` on every `v*` tag (see
[.gitea/workflows/release.yml](.gitea/workflows/release.yml)).
| Service | Port (host) | Role |
| ----------- | ----------- | ----------------------------------------------- |
| `comfyui` | `8188` | ComfyUI server + native web UI |
| `open-webui`| `3000` | Multi-user chat with txt2img / img2img panel |
## Repository layout
Open WebUI submits ComfyUI workflows directly via the documented integration —
no MCP shim, no API translation layer. Workflow templates live in
[`workflows/`](workflows/) and get pasted into Open WebUI's admin panel during
setup.
| Path | What |
| -------------------------- | ----------------------------------------------------- |
| `Dockerfile` | ComfyUI on NVIDIA, manual-install pattern |
| `workflows/` | txt2img + img2img workflow JSONs and node mappings |
| `deployments/ai-stack/` | The deployment — compose, Caddyfile, env, model preseed |
| `.gitea/workflows/` | Release pipeline (build & push image on tag) |
## Quick start
## Deploy
```sh
cp .env.example .env
# edit .env — set OPEN_WEBUI_SECRET_KEY at minimum
docker compose up -d
```
`compose up` pulls the prebuilt ComfyUI image from
`git.anomalous.dev/alphacentri/comfyui-nvidia` (CI publishes it on every
`v*` tag — see [.gitea/workflows/release.yml](.gitea/workflows/release.yml)).
Use `docker compose build` to rebuild locally when iterating on the Dockerfile.
Then drop a checkpoint into the `comfyui-models` volume and finish the Open
WebUI ComfyUI configuration. Full walkthrough in [SETUP.md](SETUP.md).
## Deployment examples
- **Repo root** (`docker-compose.yml`) — minimal `comfyui` + `open-webui`
bridge for kicking the tyres on a single-purpose box.
- **[`deployments/ai-stack/`](deployments/ai-stack/)** — production-shaped
multi-service stack: Caddy (TLS + reverse proxy), Ollama (with one-shot
model preseeding), ComfyUI, Open WebUI, optional Anubis anti-bot. Mirrors
the live `srvno.de` deployment.
The full stack — Caddy + Ollama + ComfyUI + Open WebUI (+ optional
Anubis) — lives under [`deployments/ai-stack/`](deployments/ai-stack/).
Bring-up steps, host prerequisites, Open WebUI workflow wiring, and
gotchas are in [`deployments/ai-stack/README.md`](deployments/ai-stack/README.md).
## Replaces
This repo supersedes the previous figment + segment + Forge stack. ComfyUI's
node graph covers everything those services provided (txt2img, img2img,
inpaint, mask generation via SAM/GroundingDINO custom nodes), and Open WebUI
talks to it natively.
This repo supersedes the previous figment + segment + Forge stack.
ComfyUI's node graph covers everything those services provided
(txt2img, img2img, inpaint, mask generation via SAM/GroundingDINO custom
nodes), and Open WebUI talks to it natively.
-146
View File
@@ -1,146 +0,0 @@
# Setup
End-to-end walkthrough: clean host -> running stack -> first generated image
in Open WebUI.
## 1. Host prerequisites
- Linux (or WSL2) with an NVIDIA GPU and a recent driver.
- cu126 wheels (default Dockerfile): driver >= 545
- cu130 wheels (swap in Dockerfile): driver >= 580
- Docker Engine + Compose v2.
- [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html)
installed and the Docker runtime configured (`nvidia-ctk runtime configure
--runtime=docker && systemctl restart docker`).
Confirm GPU passthrough works before bringing the stack up:
```sh
docker run --rm --gpus all nvidia/cuda:12.6.3-base-ubuntu24.04 nvidia-smi
```
## 2. Configure environment
```sh
cp .env.example .env
```
Edit `.env`:
- `OPEN_WEBUI_URL` — public URL Open WebUI is reached at (used for auth
redirects). For local-only, leave the default.
- `OPEN_WEBUI_SECRET_KEY` — generate with `openssl rand -hex 32`. Keep stable;
rotating it logs every user out.
## 3. Start the stack
```sh
docker compose up -d
```
This pulls the prebuilt `comfyui-nvidia` image from the Gitea registry (CI
publishes it on every `v*` tag) plus the upstream Open WebUI image, then
brings both up. `docker compose logs -f comfyui` should end with a line like
`To see the GUI go to: http://0.0.0.0:8188`.
To build the image locally instead (e.g. while iterating on the Dockerfile):
```sh
docker compose build comfyui
docker compose up -d
```
First local build pulls the CUDA base, PyTorch wheels, and ComfyUI source —
expect several minutes.
Health-check both services:
```sh
curl -sf http://localhost:8188/system_stats | head -c 200
curl -sf http://localhost:3000/health
```
## 4. Add at least one checkpoint
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/`:
```sh
docker run --rm -v comfyui-nvidia_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
```
Or open the ComfyUI web UI at <http://localhost:8188>, click the **Manager**
button (added by ComfyUI-Manager), and use **Model Manager** to install one
through the UI.
## 5. First-user signup in Open WebUI
Open <http://localhost:3000>. The first account created becomes the admin.
Subsequent signups land in `pending` and need admin approval (set by
`DEFAULT_USER_ROLE: pending` in compose).
## 6. Wire Open WebUI to ComfyUI
Open WebUI ships the ComfyUI integration but won't know which workflow to
submit until you paste one in. Do this once per workflow (txt2img and
img2img).
In Open WebUI: **Admin Panel -> Settings -> Images**.
1. **Image Generation Engine** -> `ComfyUI` (already preselected via env var).
2. **ComfyUI Base URL** -> `http://comfyui:8188` (already preselected).
3. **ComfyUI Workflow** -> paste the entire contents of
[`workflows/txt2img.json`](workflows/txt2img.json).
4. **ComfyUI Workflow Nodes** -> paste the contents of
[`workflows/txt2img.nodes.json`](workflows/txt2img.nodes.json).
5. **Default Model** -> the filename of the checkpoint you dropped in step 4
(e.g. `v1-5-pruned-emaonly.safetensors`).
6. Save.
For image editing (img2img), scroll to the **Image Editing** section in the
same panel and repeat with [`workflows/img2img.json`](workflows/img2img.json)
and [`workflows/img2img.nodes.json`](workflows/img2img.nodes.json).
## 7. Test it
In any chat, click the image-generation button and prompt for an image. Open
WebUI submits the workflow to ComfyUI; the result drops back into the chat
when KSampler finishes. To test img2img, attach an image and use the edit
action.
## How the workflow node mappings work
Open WebUI doesn't introspect the workflow graph. The `*.nodes.json` files
tell it which node IDs and input fields to overwrite when the user provides
a prompt, image, seed, etc. Each entry:
```json
{ "type": "<placeholder>", "node_ids": ["<id>"], "key": "<input field>" }
```
Recognised `type` strings (per Open WebUI source): `model`, `prompt`,
`negative_prompt`, `width`, `height`, `n` (batch size), `steps`, `seed`, and
`image` (img2img / edit only).
If you swap in a fancier workflow (SDXL, Flux, ControlNet, custom samplers,
NL masking via SAM nodes, etc.), update the matching `*.nodes.json` so the
node IDs and input keys still line up.
## Common gotchas
- **"Model not found" in Open WebUI's image panel.** ComfyUI lists models from
`/opt/comfyui/models/checkpoints/`. Confirm the file is there and matches
the **Default Model** field exactly (filename including extension).
- **Out-of-memory on first generate.** Lower `IMAGE_SIZE` in compose
(e.g. `768x768`) or pass `--lowvram` / `--medvram` in the Dockerfile CMD.
- **Custom nodes need extra pip packages.** Install via ComfyUI-Manager (it
pip-installs into the container's venv). Persisted because
`/opt/comfyui/custom_nodes` is a named volume — but the venv at `/opt/venv`
is not, so packages added by the manager survive container restarts only if
the manager re-installs them on boot. For permanent custom-node deps, add a
`RUN pip install ...` to the Dockerfile and rebuild.
- **GPU not visible inside container.** Re-run the `nvidia-smi` test in step
1. If it fails, the toolkit is misconfigured.
+151 -29
View File
@@ -1,12 +1,12 @@
# ai-stack — combined deployment example
# ai-stack — deployment
The full multi-service stack: Caddy (TLS + reverse proxy) in front of Open
WebUI (chat + image generation panel), Ollama (LLMs), and ComfyUI (image
generation), with an optional Anubis PoW anti-bot sidecar. One GPU host,
one bridge network, one TLS entry point.
This is what runs in production for the `srvno.de` deployment, sanitized
for sharing.
This is the only supported deployment shape — sanitized snapshot of the
production `srvno.de` deployment.
## Files
@@ -17,43 +17,165 @@ for sharing.
| `init-models.sh` | Models to preseed into Ollama on first boot |
| `.env.example` | Secrets and image-tag pins. Copy to `.env` |
## Bring it up
## 1. Host prerequisites
- Linux (or WSL2) with an NVIDIA GPU and a recent driver.
- cu126 wheels (default Dockerfile): driver >= 545
- cu130 wheels (swap in Dockerfile): driver >= 580
- Docker Engine + Compose v2.
- [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html)
installed and the Docker runtime configured (`nvidia-ctk runtime configure
--runtime=docker && systemctl restart docker`).
- DNS for the chat / ComfyUI hostnames already pointing at this host
(Caddy needs working DNS to provision Let's Encrypt certs on first boot).
Confirm GPU passthrough works before bringing the stack up:
```sh
docker run --rm --gpus all nvidia/cuda:12.6.3-base-ubuntu24.04 nvidia-smi
```
## 2. Configure
```sh
cp .env.example .env
# edit .env — generate the two keys with `openssl rand -hex 32`
# generate the two keys with: openssl rand -hex 32
```
# edit Caddyfile — replace example.com hostnames with yours, replace the
# basic_auth bcrypt placeholder, point DNS at this host
Then edit:
# edit init-models.sh — keep the models you want, drop the rest
- **`.env`** — fill in `WEBUI_SECRET_KEY` and (if using Anubis) `ANUBIS_OWUI_KEY`.
Optionally pin `COMFYUI_IMAGE_TAG` to a specific `v*` release instead of
`latest`.
- **`Caddyfile`** — replace the `chat.example.com` and `comfyui.example.com`
hostnames with yours; replace `REPLACE_WITH_BCRYPT_HASH` with a real
bcrypt hash:
```sh
docker run --rm caddy:latest caddy hash-password --plaintext 'your-password'
```
- **`init-models.sh`** — keep the LLMs you want preseeded, drop the rest.
Check sizes at <https://ollama.com/library> first; the host needs disk
for everything listed.
- **`docker-compose.yml`** — update `WEBUI_URL` and `COOKIE_DOMAIN` to
match the hostnames you set in the Caddyfile.
## 3. Bring it up
```sh
docker compose up -d
docker compose logs -f
```
First boot: Caddy provisions Let's Encrypt certs (DNS must already point
here), the model-init container pulls the LLMs listed in `init-models.sh`
(can take a while — `mistral-nemo:12b` is ~7 GB), and ComfyUI initialises
its volumes empty. Drop a checkpoint into the `comfyui-models` volume
under `checkpoints/` before the first image generation — see the repo
root [SETUP.md](../../SETUP.md) §4.
First boot: Caddy provisions Let's Encrypt certs, the `model-init`
container pulls the LLMs in `init-models.sh` (slow — `mistral-nemo:12b`
alone is ~7 GB), and ComfyUI initialises empty volumes.
After Open WebUI is up, finish the ComfyUI integration via the admin
panel — paste the four workflow JSONs from [`../../workflows/`](../../workflows/).
See [SETUP.md §6](../../SETUP.md).
Health-check:
## What's different from the upstream `comfyui-nvidia` standalone compose
```sh
docker compose exec comfyui curl -sf http://127.0.0.1:8188/system_stats | head -c 200
docker compose exec open-webui curl -sf http://127.0.0.1:8080/health
```
The standalone compose at the repo root is just `comfyui` + `open-webui`
on a fresh bridge — meant for kicking the tyres or running ComfyUI on a
single-purpose box. This deployment adds:
## 4. Drop in at least one ComfyUI checkpoint
- **Caddy** with auto-TLS, so Open WebUI and ComfyUI are reachable on
real hostnames over HTTPS instead of `localhost:3000`.
- **Ollama** for chat models, with a one-shot `model-init` puller that
preseeds whatever `init-models.sh` lists.
- **Anubis** anti-bot stub for protected hostnames (commented in by
default; uncomment + provide a key to activate).
- No host ports published for ComfyUI or Open WebUI — Caddy is the only
service bound to 80/443.
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/`:
```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
```
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**.
## 5. First-user signup in Open WebUI
Open `https://chat.example.com`. The first account created becomes the
admin. Subsequent signups land in `pending` and need admin approval (set
by `DEFAULT_USER_ROLE: pending` in compose).
## 6. Wire Open WebUI to ComfyUI
Open WebUI ships the ComfyUI integration but won't know which workflow to
submit until you paste one in. Do this once for txt2img, once for img2img.
In Open WebUI: **Admin Panel -> Settings -> Images**.
1. **Image Generation Engine** -> `ComfyUI` (preselected via env var).
2. **ComfyUI Base URL** -> `http://comfyui:8188` (preselected).
3. **ComfyUI Workflow** -> paste the entire contents of
[`../../workflows/txt2img.json`](../../workflows/txt2img.json).
4. **ComfyUI Workflow Nodes** -> paste the contents of
[`../../workflows/txt2img.nodes.json`](../../workflows/txt2img.nodes.json).
5. **Default Model** -> the filename of the checkpoint you dropped in
step 4 (e.g. `v1-5-pruned-emaonly.safetensors`).
6. Save.
For image editing (img2img), scroll to the **Image Editing** section in
the same panel and repeat with
[`../../workflows/img2img.json`](../../workflows/img2img.json) and
[`../../workflows/img2img.nodes.json`](../../workflows/img2img.nodes.json).
## 7. Test it
In any chat, click the image-generation button and prompt for an image.
Open WebUI submits the workflow to ComfyUI; the result drops back into
the chat when KSampler finishes. To test img2img, attach an image and
use the edit action.
## Enabling Anubis (later)
The `anubis-owui` service is defined in compose but no Caddy site block
points at it yet. To activate:
1. Generate a key: `openssl rand -hex 32` and set `ANUBIS_OWUI_KEY` in `.env`.
2. In `Caddyfile`, change `reverse_proxy open-webui:8080` to
`reverse_proxy anubis-owui:8923` for the chat hostname.
3. `docker compose up -d`.
## How the workflow node mappings work
Open WebUI doesn't introspect the workflow graph. The `*.nodes.json`
files tell it which node IDs and input fields to overwrite when the user
provides a prompt, image, seed, etc. Each entry:
```json
{ "type": "<placeholder>", "node_ids": ["<id>"], "key": "<input field>" }
```
Recognised `type` strings (per Open WebUI source): `model`, `prompt`,
`negative_prompt`, `width`, `height`, `n` (batch size), `steps`, `seed`,
and `image` (img2img / edit only).
If you swap in a fancier workflow (SDXL, Flux, ControlNet, custom
samplers, NL masking via SAM nodes, etc.), update the matching
`*.nodes.json` so the node IDs and input keys still line up.
## Common gotchas
- **"Model not found" in Open WebUI's image panel.** ComfyUI lists
models from `/opt/comfyui/models/checkpoints/`. Confirm the file is
there and that **Default Model** matches the filename exactly
(including extension).
- **Out-of-memory on first generate.** Lower `IMAGE_SIZE` in compose
(e.g. `768x768`) or pass `--lowvram` / `--medvram` in the Dockerfile
CMD and rebuild.
- **Custom nodes need extra pip packages.** Install via ComfyUI-Manager
(it pip-installs into the container's venv). The `custom_nodes`
volume persists, but `/opt/venv` does not — so packages installed by
the manager survive container restarts only because the manager
re-installs them on boot. For permanent custom-node deps, add a
`RUN pip install …` to the Dockerfile and rebuild.
- **GPU not visible inside container.** Re-run the `nvidia-smi` test in
step 1. If it fails, the toolkit is misconfigured.
- **Caddy can't get a cert.** First-boot ACME requires DNS A/AAAA
records pointing at this host's public IP and ports 80+443 reachable
from the internet. Check `docker compose logs caddy` for the specific
challenge failure.
-110
View File
@@ -1,110 +0,0 @@
# comfyui-nvidia — ComfyUI image-generation backend fronted by Open WebUI.
#
# Open WebUI provides the multi-user chat UI and a built-in image-generation
# panel that submits ComfyUI workflows directly. Two workflow templates ship in
# workflows/ — txt2img.json and img2img.json. Paste them (and the matching
# node-mapping JSON) into the Open WebUI admin panel under
# Settings -> Images. See SETUP.md.
#
# Single GPU, single host. Both services share the comfyui-net bridge so Open
# WebUI addresses ComfyUI by service name (http://comfyui:8188).
name: comfyui-nvidia
networks:
comfyui-net:
driver: bridge
volumes:
comfyui-models: # /opt/comfyui/models (checkpoints, vae, loras, ...)
comfyui-custom-nodes: # /opt/comfyui/custom_nodes
comfyui-input: # /opt/comfyui/input (uploaded source images)
comfyui-output: # /opt/comfyui/output (generated images)
comfyui-user: # /opt/comfyui/user (saved workflows, settings)
open-webui-data: # Open WebUI accounts, chats, settings
services:
comfyui:
# CI (.gitea/workflows/release.yml) builds and pushes this image on tag.
# `build:` is kept so `docker compose build` still works locally — useful
# when iterating on the Dockerfile without going through CI.
image: git.anomalous.dev/alphacentri/comfyui-nvidia:${COMFYUI_IMAGE_TAG:-latest}
pull_policy: always
build:
context: .
dockerfile: Dockerfile
container_name: comfyui
restart: unless-stopped
networks: [comfyui-net]
ports:
# Optional on the host — Open WebUI reaches comfyui:8188 over the bridge.
# Keep it published if you also want to use ComfyUI's native web UI at
# http://localhost:8188.
- "8188:8188"
volumes:
- comfyui-models:/opt/comfyui/models
- comfyui-custom-nodes:/opt/comfyui/custom_nodes
- comfyui-input:/opt/comfyui/input
- comfyui-output:/opt/comfyui/output
- comfyui-user:/opt/comfyui/user
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
healthcheck:
test: ["CMD", "curl", "-sf", "http://127.0.0.1:8188/system_stats"]
interval: 30s
timeout: 5s
retries: 5
start_period: 120s
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui
restart: unless-stopped
networks: [comfyui-net]
ports:
- "3000:8080"
extra_hosts:
# So Open WebUI can reach an Ollama instance running on the VM host.
# Drop this if you don't run Ollama on the host.
- "host.docker.internal:host-gateway"
depends_on:
comfyui:
condition: service_started
environment:
WEBUI_AUTH: "true"
ENABLE_SIGNUP: "true"
DEFAULT_USER_ROLE: "pending"
# Public URL used for auth redirects and email-link generation. Set this
# to whatever your reverse proxy terminates.
WEBUI_URL: "${OPEN_WEBUI_URL:-http://localhost:3000}"
# Cookie-signing key. Stable across restarts (rotating it logs every
# user out). Generate once: openssl rand -hex 32
WEBUI_SECRET_KEY: "${OPEN_WEBUI_SECRET_KEY:-change-me-please}"
# Optional: Ollama on the VM host for chat. Comment out if unused.
OLLAMA_BASE_URL: "http://host.docker.internal:11434"
# Image generation via ComfyUI. The workflow JSON and node-mapping JSON
# are configured through the admin UI — see SETUP.md for the paste-in
# values. Only the engine selection and base URL are wired here so the
# admin panel comes up pre-pointed at the right backend.
ENABLE_IMAGE_GENERATION: "true"
IMAGE_GENERATION_ENGINE: "comfyui"
COMFYUI_BASE_URL: "http://comfyui:8188"
IMAGE_SIZE: "1024x1024"
IMAGE_STEPS: "20"
volumes:
- open-webui-data:/app/backend/data
healthcheck:
test: ["CMD", "curl", "-sf", "http://127.0.0.1:8080/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 60s