您现在的位置是:网站首页> AI人工智能
Comfy UI 技术收集
- AI人工智能
- 2026-05-31
- 907人已阅读
Comfy UI 技术收集

ComfyUI 模型默认都放在安装目录下的 models 文件夹里,不同类型模型需存入对应子文件夹。
模型分类存放位置:
1.大模型(Checkpoints):放入 models/checkpoints/,这是最常用的主模型目录 。
2.LoRA 模型:放入 models/loras/,用于微调风格或人物 。
3.ControlNet 模型:放入 models/controlnet/,用于控制构图和姿势 。
4.VAE 模型:放入 models/vae/,负责图像解码和色彩还原 。
5.放大模型:放入 models/upscale_models/,用于高清修复 。
6.其他模型:如 embeddings(嵌入)、clip(文本编码器)、unet、video_models(视频模型)等,均有对应名称的子文件夹
ComfyUI API 节点为何看到custom_nodes 目录里很多子目录,而主目录下.py很少
1.LoRA 模型
相当于贴纸 / 风格滤镜。底模是基础画风,LoRA 可以额外加指定人物、服饰、画风,比如 “某动漫角色”“汉服”,叠加上去就行,体积很小。
2.ControlNet
相当于打草稿的线稿 / 骨架。正常 AI 自由发挥,ControlNet 强制它按照你给的姿势、轮廓、透视来画,避免人物肢体畸形。
3.种子 (Seed)
生成雪花图的 “随机编号”。同一个种子 + 同样参数,每次生成的初始雪花一模一样,最终画面也基本一致;改种子,雪花就变了,画出来的图也不一样。
4.CFG 数值
可以理解为 AI 听不听提示词的严格程度。数值越高,AI 越死板遵守文字描述;太低就会放飞自我,画得和文字不搭。
一句话说清:Checkpoint(简称 CKPT)就是 SD 的 “完整大模型 / 底模”,是训练时存的权重快照,一个文件打包了生成图像必需的三大核心组件。
一、它到底是什么
全称:Checkpoint(检查点模型),俗称底模 / 大模型。
本质:训练过程中定期保存的完整模型权重,相当于游戏的 “存档”。
内容:一个文件里包含三样东西(缺一不可):
MODEL(UNet):负责去噪、构图、细节、光影(紫色端口)。
CLIP:负责把文字转成向量,理解提示词(黄色端口)。
VAE:负责把潜变量解码成清晰图像(粉色端口)。
格式:.ckpt(旧)或 .safetensors(新、更安全、更快)。
大小:2–7GB(SD1.5≈4GB,SDXL≈7GB)。
二、在 ComfyUI 里的位置与作用
存放路径:ComfyUI/models/checkpoints/。
对应节点:Load Checkpoint(CheckpointLoaderSimple)。
输出端口:
MODEL → 给 KSampler(去噪)
CLIP → 给 CLIP Text Encode(提示词)
VAE → 给 VAE Decode(出图)
地位:所有生成的起点;你选哪个 Checkpoint,基本就决定了画面风格上限(写实、动漫、插画、科幻等)。
三、和 LoRA/VAE/ControlNet 的区别(关键)
✅ Checkpoint(底模):完整大模型,决定基础风格 + 画质;必选,一次只加载一个。
✅ LoRA(小模型):微调插件(几十 MB),在底模上叠加特定风格 / 人物 / 服饰;可选,可多个叠加。
✅ VAE:画质增强插件(几百 MB),专门优化色彩、锐度、细节;常随底模打包,也可单独换。
✅ ControlNet:结构控制插件(几百 MB),控姿势、构图、透视;可选。
四、常见 Checkpoint 类型(新手够用)
SD 1.5:最通用、兼容所有 LoRA/ControlNet;写实 / 动漫通吃。
SDXL 1.0:画质更高、细节更好、支持 1024+ 分辨率;需更强显卡。
写实类:Realistic Vision、Deliberate、MeinaMix(真人质感强)。
动漫类:Anything-V3、AbyssOrangeMix、ToonYou(二次元风格)。
五、为什么它叫 Checkpoint
训练大模型要跑几周甚至几个月,中途会每几小时 / 几轮存一次档,防止断电 / 崩了重跑。
这些存档就叫 Checkpoint;最后选效果最好的那个作为正式发布的底模。
六、快速记忆
Checkpoint = 完整底模 = 风格地基。
一个文件 = UNet + CLIP + VAE。
ComfyUI 里 Load Checkpoint 就是加载它,输出紫 / 黄 / 粉三个端口,连到后续节点。
Checkpoint 里打包了两个东西 ——UNet(大模型)+ CLIP(文本编码器);所以要先把 CLIP “取出来”,才能用它去编码你的文字。
你现在的困惑,来自把 “模型权重” 和 “数据流向” 搞混了。我分两层讲:
一、权重层面:Checkpoint = 打包好的一套 “工具”
一个 SD 大模型文件(.safetensors/.ckpt)里,同时存了三个独立子模型的权重:
MODEL(UNet):真正的画图大模型(负责去噪、生成图像)
CLIP:文本编码器(负责把文字→向量)
VAE:解码器(把潜变量→图片)
它们是并列关系,不是谁输入给谁;只是被打包在同一个文件里一起发布。
所以:
Load Checkpoint 的作用:把这三个子模型从文件里拆出来,变成可用的 “工具”
输出三个端口:MODEL、CLIP、VAE(都是 “工具 / 权重”,不是数据)
二、数据流向层面:文字 → CLIP → 向量 → UNet(才是你要的)
正确顺序(数据流动):
1.你输入文本(正向 / 反向提示词)
2.CLIP Text Encode 节点:
输入:CLIP(来自 Checkpoint 的权重) + 你的文字
输出:文本向量(conditioning)
3.KSampler(UNet):
输入:MODEL(UNet 权重) + 文本向量 + 噪声
输出:去噪后的潜变量
4.VAE Decode:
输入:VAE 权重 + 潜变量
输出:最终图片
下面我用最直接、可复制就能跑的方式,把 ComfyUI 本地 API 讲透(不绕云服务)。
一、ComfyUI API 本质一句话
ComfyUI 自带 HTTP+WebSocket API,你不需要装任何插件,启动后直接可用:
地址:http://localhost:8188
核心:把 “工作流 JSON” 发进去 → 排队执行 → 轮询 / WS 拿结果
二、先准备:导出 API 格式的工作流
1.在 ComfyUI 里搭好你的图生图 / 文生图流程
2.菜单 → Save (API Format)

3.得到一个 workflow_api.json(不带界面坐标,纯节点数据)
关键点:
普通 Save → 带界面坐标(不能直接给 API 用)
Save (API Format) → 纯执行数据(API 专用)
三、核心接口(必记)
1. 提交任务(最重要)
POST /prompt
作用:下发工作流,返回 prompt_id(任务唯一 ID)
请求体(JSON)
json
{
"client_id": "my-test-client",
"prompt": {
"3": {
"class_type": "KSampler",
"inputs": {
"seed": 12345,
"steps": 20,
"cfg": 7,
"sampler_name": "euler",
"scheduler": "normal",
"denoise": 1,
"model": ["4", 0],
"positive": ["6", 0],
"negative": ["7", 0],
"latent_image": ["5", 0]
}
},
"4": { "class_type": "CheckpointLoaderSimple", "inputs": { "ckpt_name": "v1-5-pruned-emaonly.safetensors" } },
"5": { "class_type": "EmptyLatentImage", "inputs": { "width": 512, "height": 512, "batch_size": 1 } },
"6": { "class_type": "CLIPTextEncode", "inputs": { "text": "a beautiful cat", "clip": ["4", 1] } },
"7": { "class_type": "CLIPTextEncode", "inputs": { "text": "ugly, blurry", "clip": ["4", 1] } },
"8": { "class_type": "VAEEncode", "inputs": { "vae": ["4", 2], "pixels": ["9", 0] } },
"9": { "class_type": "LoadImage", "inputs": { "image": "input.jpg" } }
}
}
返回
json
{
"prompt_id": "xxxx-xxxx-xxxx",
"number": 1,
"node_errors": {}
}
2. 查询任务状态
GET /history/{prompt_id}
作用:看任务是否完成、结果图片地址
3. WebSocket 实时进度(推荐)
地址:ws://localhost:8188/ws?client_id=my-test-client
作用:实时收到:
进度(%)
预览图
完成 / 失败通知
四、Python 调用示例(复制就能跑)
1. 提交任务
python
运行
import requests
import json
API_URL = "http://localhost:8188"
CLIENT_ID = "my-test-client"
# 1. 读取 API 工作流
with open("workflow_api.json", "r", encoding="utf-8") as f:
workflow = json.load(f)
# 2. 修改参数(例如改提示词、种子)
workflow["6"]["inputs"]["text"] = "a beautiful dog" # CLIPTextEncode
workflow["3"]["inputs"]["seed"] = 98765
# 3. 提交
resp = requests.post(
f"{API_URL}/prompt",
json={"client_id": CLIENT_ID, "prompt": workflow}
)
prompt_id = resp.json()["prompt_id"]
print("任务ID:", prompt_id)
2. 轮询结果
python
运行
import time
def get_result(prompt_id):
while True:
resp = requests.get(f"{API_URL}/history/{prompt_id}")
data = resp.json()
if prompt_id in data:
return data[prompt_id]["outputs"]
time.sleep(1)
outputs = get_result(prompt_id)
print("输出:", outputs)
# 图片地址示例:http://localhost:8188/view?filename=xxx.png
五、常见坑(你一定会遇到)
1.普通 Save 的 JSON 不能用 → 必须 Save (API Format)
2.节点 ID 不能乱改 → JSON 里的 "3"/"4"/"5" 是节点 ID,连线靠它
3.模型路径要对 → CheckpointLoaderSimple 的 ckpt_name 必须是 models/checkpoints/ 里的文件名
4.跨域 → 前端调用要加:
plaintext
--enable-cors-header
启动命令:python main.py --enable-cors-header
六、你之前的疑问(结合 API)
你问:为什么是大模型输出给 CLIP?
在 API JSON 里看:
json
"4": { "class_type": "CheckpointLoaderSimple", ... } # 输出 MODEL/CLIP/VAE
"6": { "class_type": "CLIPTextEncode", "inputs": { "clip": ["4", 1] } }
["4",1] → 节点 4(Checkpoint)的第 1 个输出(CLIP)
传的是CLIP 权重,不是数据
数据流向:text → CLIP (权重) → vector → MODEL (权重) → image
可以,而且很简单:ComfyUI 的 “节点” 本身就是为 API 设计的,你写的自定义节点天然支持 API 调用,不需要额外改造。下面从原理→最小示例→API 调用→常见坑,一步到位讲清楚。
一、核心结论
ComfyUI 节点 = Python 类 + 固定接口规范
放在 custom_nodes/ 下,重启自动注册,UI/API 都能用
你写的节点:
在界面:出现在右键菜单、可连线
在 API:出现在 prompt JSON 里,直接调用
二、写一个 “自定义 API 节点”(最小可运行)
1. 新建文件
路径:ComfyUI/custom_nodes/my_api_nodes.py
2. 完整代码(复制即用)
python
运行
# my_api_nodes.py
class StringToUpper:
"""自定义节点:把字符串转大写(UI/API 通用)"""
# 1. 定义输入(API 会校验这个结构)
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text": ("STRING", {"default": "hello comfyui api"}),
}
}
# 2. 定义输出类型
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("upper_text",)
# 3. 执行函数(API 最终调用的逻辑)
FUNCTION = "run"
# 4. 菜单分类
CATEGORY = "my_api_tools"
def run(self, text):
return (text.upper(),)
# 注册节点(必须,否则 UI/API 看不到)
NODE_CLASS_MAPPINGS = {
"StringToUpper": StringToUpper
}
# 显示名称(可选)
NODE_DISPLAY_NAME_MAPPINGS = {
"StringToUpper": "字符串转大写(API可用)"
}
3. 重启 ComfyUI
启动时会加载 custom_nodes/ 下所有 Python 文件
左侧菜单出现:my_api_tools → 字符串转大写(API可用)
三、用 API 调用你的自定义节点
1. 导出 API 格式工作流
界面拖入:StringToUpper + 你需要的其他节点
菜单 → Save (API Format) → 得到 workflow_api.json
2. API JSON 示例(核心部分)
json
{
"client_id": "my-test",
"prompt": {
"1": {
"class_type": "StringToUpper",
"inputs": {
"text": "hello from api"
}
}
}
}
class_type = 你注册的类名 StringToUpper
inputs 和你 INPUT_TYPES 完全一致
3. Python 调用(和官方节点无区别)
python
运行
import requests
import json
API_URL = "http://localhost:8188"
workflow = {
"client_id": "my-test",
"prompt": {
"1": {
"class_type": "StringToUpper",
"inputs": {"text": "hello comfyui api"}
}
}
}
resp = requests.post(f"{API_URL}/prompt", json=workflow)
print(resp.json())
返回结果会包含 upper_text: "HELLO COMFYUI API"
四、支持复杂类型(如 CLIP、MODEL、IMAGE)
你之前关心的 CLIP / 文本编码,自定义节点也能对接:
python
运行
class MyCLIPTextEncode:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text": ("STRING", {"multiline": True}),
"clip": ("CLIP",) # 直接接收 Checkpoint 输出的 CLIP
}
}
RETURN_TYPES = ("CONDITIONING",)
FUNCTION = "encode"
CATEGORY = "my_api_tools"
def encode(self, text, clip):
# 调用 ComfyUI 原生 CLIP 编码逻辑
tokens = clip.tokenize(text)
cond = clip.encode_from_tokens(tokens, return_pooled=True)
return (cond,)
API 里连线:CheckpointLoader → MyCLIPTextEncode (clip输入)
完全遵循原生数据流向:text → CLIP → CONDITIONING → KSampler
五、常见坑(避坑)
必须注册:NODE_CLASS_MAPPINGS 不能少,否则 API 找不到节点
类型严格:INPUT_TYPES/RETURN_TYPES 必须和实际数据匹配(如 CLIP/MODEL/IMAGE)
API 专用导出:必须用 Save (API Format),普通 Save 带 UI 坐标,API 不认
重启生效:修改自定义节点代码后,必须重启 ComfyUI
六、一句话总结
写自定义节点 = 写带固定接口的 Python 类,放在 custom_nodes 目录,天然支持 UI 和 API,没有额外步骤。你可以封装任何逻辑:文本处理、模型加载、API 接口调用、CLIP 编码定制等。
ComfyUI API 节点为何看到custom_nodes 目录里很多子目录,而主目录下.py很少
一句话:因为 ComfyUI 把 “每个自定义节点包” 都当成一个独立 Python 模块(文件夹)来加载,所以都是子目录,主目录很少直接放 .py。下面把原理、规范、现状都说清楚。
一、加载机制:它只扫 “目录包”,不扫散文件
ComfyUI 启动时对 custom_nodes/ 的逻辑是:
遍历 custom_nodes/ 下的每一个子文件夹
对每个子文件夹,看里面有没有 __init__.py
有 → 当成一个 Python 模块包,执行导入,读取 NODE_CLASS_MAPPINGS,注册节点
主目录里直接放的 .py,默认不会被自动加载(除非你手动改启动代码)
所以:
子目录多 = 装了很多节点插件(每个插件一个文件夹)
主目录 .py 少 = 大家都按规范做成 “目录包”,不扔散文件
二、标准结构:一个插件 = 一个文件夹
正规自定义节点(比如 ControlNet、Impact Pack、FaceDetailer)都长这样:
plaintext
custom_nodes/
├── comfyui_controlnet_aux/ # 插件A:独立子目录
│ ├── __init__.py # 必须:包入口,导出 NODE_CLASS_MAPPINGS
│ ├── nodes.py # 节点代码
│ ├── utils/ # 工具子模块
│ ├── models/ # 模型/权重
│ └── js/ # 前端UI
│
├── ComfyUI-Impact-Pack/ # 插件B:独立子目录
│ ├── __init__.py
│ ├── nodes/
│ ├── ...
│
└── my_single_node.py # 很少见:直接放主目录的散文件(不推荐)
为什么要这样?
依赖隔离:每个插件自己的 utils、models、js 不打架
方便安装 / 卸载:删一个文件夹 = 彻底卸载插件
前后端分离:js 放在子目录,ComfyUI 能自动找到并加载前端组件
版本管理:每个插件独立更新,互不影响
三、为什么你看到 “主目录 .py 很少”
官方推荐规范:所有成熟插件都做成 “目录包”,没人往主目录扔散文件
散文件有坑:
主目录 .py 不会自动加载,要手动改代码
容易命名冲突(两个插件都叫 utils.py)
没法带 js、models、依赖文件
你装的都是成熟插件:ControlNet、Impact Pack、FaceDetailer 等,全是子目录形式
四、你自己写节点:两种玩法
1)简单单文件(临时测试)
直接扔 custom_nodes/my_test.py:
python
运行
# my_test.py
class HelloNode:
INPUT_TYPES = lambda: {"required": {"text": ("STRING", {"default": "hi"})}}
RETURN_TYPES = ("STRING",)
FUNCTION = "run"
CATEGORY = "test"
def run(self, text):
return (text,)
NODE_CLASS_MAPPINGS = {"HelloNode": HelloNode}
⚠️ 缺点:要手动在 __init__.py 里 import,否则不加载;没法带前端 js。
2)标准目录包(推荐,和主流插件一致)
plaintext
custom_nodes/my_plugin/
├── __init__.py
└── nodes.py
__init__.py:
python
运行
from .nodes import *
NODE_CLASS_MAPPINGS = {
"HelloNode": HelloNode
}
nodes.py 写节点类。
✅ 优点:自动加载、可加 js/utils/models、规范、API/UI 都正常。
五、总结
子目录多:每个子目录 = 一个独立插件包(标准做法)
主目录 .py 少:没人用散文件,都按规范做目录包
核心原因:ComfyUI 按 “Python 模块包(带 init.py 的文件夹)” 加载自定义节点
要不要我帮你把之前写的那个自定义节点,改成标准目录包结构,并附上完整 __init__.py,你直接放进去就能自动加载?
下面用通俗语言 + 完整流程 + 可直接跑的 Python 示例,把「用 WebSocket 调用 ComfyUI」讲清楚。
(核心:发任务用 HTTP POST /prompt,看进度和结果用 WebSocket /ws)
一、原理一句话讲明白
ComfyUI 的 API 是「HTTP 发任务,WebSocket 收实时进度 + 结果」:
HTTP POST /prompt:把你做好的工作流 JSON 发过去,让它开始画图;
WebSocket /ws?client_id=xxx:连上这个地址,全程监听:
队列状态、正在跑哪个节点、采样进度(%);
实时预览图(二进制);
最终生成图片的地址;
全程WebSocket 只收不发,任务是 HTTP 提交的。
二、关键地址(默认)
服务器地址:http://127.0.0.1:8188
提交任务:POST http://127.0.0.1:8188/prompt
监听进度:ws://127.0.0.1:8188/ws?client_id=随便一个唯一ID(UUID)
三、准备工作(3 步)
1. 开启 ComfyUI 并允许跨域(否则外部连不上)
启动时加参数:
bash
运行
python main.py --enable-cors-header
2. 导出工作流为「API 格式 JSON」
在 ComfyUI 里调好图生图 / 文生图流程;
菜单 → Save (API Format) → 保存成 workflow.json;
这个 JSON 就是你要 POST 出去的内容。
3. 安装依赖
bash
运行
pip install websockets requests
四、完整流程(带代码,直接能用)
1. 生成唯一 client_id(用来绑定 WebSocket 和任务)
python
运行
import uuid
client_id = str(uuid.uuid4()) # 例如:'f47ac10b-58cc-4372-a567-0e02b2c3d479'
2. 加载并修改工作流(动态改提示词 / 尺寸)
python
运行
import json
# 读取你导出的 API 工作流
with open("workflow.json", "r", encoding="utf-8") as f:
prompt = json.load(f)
# 示例:改正向提示词(节点ID看你自己的,比如"6"是CLIP文本编码器)
prompt["6"]["inputs"]["text"] = "a beautiful girl, blue hair, masterpiece"
# 改反向提示词
prompt["7"]["inputs"]["text"] = "ugly, low quality"
# 改宽高
prompt["5"]["inputs"]["width"] = 768
prompt["5"]["inputs"]["height"] = 1024
3. HTTP POST 提交任务
python
运行
import requests
server = "http://127.0.0.1:8188"
payload = {
"prompt": prompt,
"client_id": client_id # 关键!绑定 WebSocket
}
res = requests.post(f"{server}/prompt", json=payload)
res_data = res.json()
prompt_id = res_data["prompt_id"] # 任务唯一ID,后面过滤用
print("任务已提交,prompt_id:", prompt_id)
4. WebSocket 监听进度 + 结果(核心)
python
运行
import asyncio
import websockets
import json
async def listen():
uri = f"ws://127.0.0.1:8188/ws?client_id={client_id}"
async with websockets.connect(uri) as ws:
while True:
msg = await ws.recv()
# 先判断是文本还是二进制
if isinstance(msg, bytes):
# 二进制 = 预览图,可保存/显示
print("收到预览图(二进制)")
continue
data = json.loads(msg)
msg_type = data["type"]
msg_data = data["data"]
# 只处理我们这个 prompt_id 的消息
if msg_data.get("prompt_id") != prompt_id:
continue
# 1. 队列状态更新
if msg_type == "status":
queue_len = msg_data["status"]["exec_info"]["queue_remaining"]
print(f"队列剩余任务:{queue_len}")
# 2. 开始执行某个节点
elif msg_type == "executing":
node = msg_data["node"]
if node is None:
print("✅ 任务执行完成!")
break
print(f"正在执行节点:{node}")
# 3. 采样进度(最常用)
elif msg_type == "progress":
value = msg_data["value"]
max_val = msg_data["max"]
print(f"采样进度:{value}/{max_val}")
# 4. 最终结果(图片/视频地址)
elif msg_type == "execution_success":
print("🎉 生成成功!结果:")
print(json.dumps(msg_data, indent=2))
break
# 运行监听
asyncio.run(listen())
五、WebSocket 会收到哪些消息(通俗解释)
表格
type 说明 你能拿到什么
status 队列变了 还有多少任务在等
executing 正在跑哪个节点 节点 ID(比如 KSampler)
progress 采样进度 当前步 / 总步数(如 12/20)
execution_success 全部跑完 图片文件名 / 地址
二进制数据 实时预览图 直接存为 jpg/png 就能看
六、常见坑(新手必看)
连不上 WebSocket:
启动 ComfyUI 必须加 --enable-cors-header;
防火墙放行 8188 端口;
client_id 必须和 POST /prompt 时一致。
收不到自己任务的消息:
WebSocket 消息里带 prompt_id,必须过滤,不然会收到别人的任务消息。
工作流改了代码就报错:
节点 ID(如 "6")是固定的,不要在 UI 里乱删加节点,否则 ID 变了代码要重改。
七、一句话总结
HTTP POST /prompt:发工作流,绑定 client_id;
WebSocket /ws?client_id=xxx:监听进度、预览图、最终结果;
上面代码复制就能跑,改改提示词和尺寸就能自动出图。
通俗语言 + 功能 + 参数 + 实际用法 + 连接示例,把 ComfyUI 最核心、最常用的节点一次性讲全,覆盖:模型加载、文本编码、潜空间、采样、VAE 解码、图像保存、ControlNet、LoRA 等。
一、模型加载类(必用)
1. Load Checkpoint(加载主模型)
作用:加载 SD1.5/SDXL 等大模型(.safetensors/.ckpt),一次性输出 MODEL、CLIP、VAE 三样东西。

关键参数
ckpt_name:选你的模型文件(如 realisticVisionV51.safetensors)
怎么连
MODEL → KSampler
CLIP → CLIP Text Encode
VAE → VAE Decode
2. Load LoRA(加载 LoRA)
作用:给主模型 “加风格 / 加人物 / 加细节”,相当于小插件。

ComfyUI Load LoRA节点
关键参数
lora_name:选 LoRA 文件(如 animeStyle.safetensors)
strength_model:LoRA 强度(0.6–0.8 常用)
怎么连
输入:MODEL(从 Checkpoint 来)
输出:MODEL(传给 KSampler)
3. VAE Loader(单独加载 VAE)
作用:主模型 VAE 不好时,单独换一个(如 vae-ft-mse-840000-ema-pruned.safetensors),提升色彩 / 清晰度。
怎么连:输出 VAE → VAE Decode
二、文本编码类(必用)
CLIP Text Encode(Prompt)
作用:把你写的中文 / 英文提示词,变成模型能懂的 “数字向量”(CONDITIONING)。

关键参数
text:正面提示词(如 masterpiece, 1girl, blue hair)
负面提示词另放一个节点(如 low quality, blurry)
怎么连
输入:CLIP(从 Checkpoint 来)
输出:CONDITIONING → KSampler(positive/negative)
三、潜空间 Latent 类(必用)
Empty Latent Image(空潜图)
作用:创建一张空白 “潜空间图片”(SD 真实像素 ÷8),供 KSampler 去 “画”。

关键参数
width/height:宽高(必须是 64 倍数,如 512×768、1024×1024)
怎么连:输出 LATENT → KSampler
四、核心采样器(最重要)
KSampler(标准采样器)
作用:真正画图的核心!往空潜图里反复去噪、迭代,把文字变成图像。


关键参数(必懂)
seed:随机种子(固定 = 每次出一样图;随机 = 每次不同)
steps:步数(20–30 常用;越高越慢、细节越好)
cfg:提示词强度(7–10 常用;越高越贴近提示词、但易崩)
sampler_name:采样算法(euler a 艺术感强;dpmpp_2m 真实清晰)
scheduler:调度器(normal 通用;karras 细节更好)
怎么连(标准文生图)
MODEL → 输入
positive → 正面 CONDITIONING
negative → 负面 CONDITIONING
latent_image → Empty Latent Image
输出 LATENT → VAE Decode
KSampler Advanced(高级采样)
作用:可指定起始步 / 结束步,用于局部重绘(inpaint)、图生图强度控制。

ComfyUI KSampler Advanced节点
五、VAE 解码(必用)
VAE Decode
作用:把 KSampler 输出的潜空间图(LATENT),还原成肉眼能看的 RGB 图片(IMAGE)。

怎么连
输入:LATENT(KSampler 输出)、VAE(Checkpoint 或单独 VAE Loader)
输出:IMAGE → Save Image
六、图像输出(必用)
Save Image
作用:把 IMAGE 保存成 PNG/JPG,或直接在 UI 显示。

关键参数
filename_prefix:文件名前缀(如 my_art)
七、图生图(img2img)关键节点
Load Image
作用:加载一张参考图 / 原图,用于图生图、ControlNet、IP-Adapter。

ComfyUI Load Image节点
输出:IMAGE → VAE Encode
VAE Encode
作用:把 Load Image 的 RGB 图,压缩成潜空间图(LATENT),给 KSampler 继续画。

ComfyUI VAE Encode节点
怎么连:IMAGE → VAE Encode → KSampler(latent_image)
八、ControlNet(精准控制)
ControlNet Loader
作用:加载 ControlNet 模型(如 openpose、canny、depth),控制人物姿势、构图、线条。

ComfyUI ControlNet Loader节点
ControlNet Apply
作用:把 ControlNet 模型 + 控制图(如姿势图),绑定到生成过程。

怎么连
输入:MODEL、CONTROL_NET、IMAGE(Load Image 来的控制图)、CONDITIONING
输出:MODEL → KSampler
九、最简单「文生图」工作流(直接照抄)
Load Checkpoint → 输出 MODEL、CLIP、VAE
CLIP Text Encode(正面)→ 输入 CLIP,写提示词
CLIP Text Encode(负面)→ 输入 CLIP,写负面词
Empty Latent Image → 设 512×768
KSampler → 连 MODEL、正面 / 负面 CONDITIONING、Empty Latent;steps=28、cfg=8、sampler=dpmpp_2m
VAE Decode → 连 KSampler 的 LATENT、VAE
Save Image → 连 VAE Decode 的 IMAGE

十、新手常见疑问
为什么图很糊? → 换 dpmpp_2m 采样器、步数≥25、用高质量 VAE。
提示词不生效? → CFG 调到 7–10、正面词写详细、负面词加 low quality。
SDXL 为什么要 1024×1024? → SDXL 原生训练分辨率就是 1024,512 会糊。
ComfyUI 里做视频最常用、最实用的节点,按「基础→生成→控制→后处理」顺序,用通俗语言 + 功能 + 参数 + 怎么连 + 实战用法一次性讲全。(含:AnimateDiff、SVD、Wan、帧处理、ControlNet、插帧、保存)
一、视频基础节点(必装、必用)
1. Load Video(加载视频)
作用:把现有视频读进来,拆成一帧帧图片(IMAGE 序列)。
常用参数
video_path:选你的 MP4/WebM
start_frame/end_frame:截取片段
frame_step:跳帧(= 隔几帧取一帧,加快处理)
怎么连
输出:IMAGE(帧序列) → 给 ControlNet / 图生图 / 风格迁移
2. Video2Frames / Load Image Batch(帧序列)
作用:把「文件夹里的一堆图片」当成视频帧输入。
用法:出图→存文件夹→用这个节点读进来→做视频。
3. Frames2Video / Video Combine(帧→视频)
作用:把一堆图片(IMAGE 序列)拼成 MP4/GIF/WebP。
关键参数
frame_rate(fps):8–24(常用 12,流畅又不卡)
crf:画质(23 = 高清,28 = 普通)
怎么连
IMAGE 序列 → 输入 → 输出视频文件
4. Save Animated WEBP / PNG(存动图)
作用:直接输出动图,适合发朋友圈 / 公众号。
二、AnimateDiff(最主流、显存友好:8G 可跑)
1. Load AnimateDiff Model(加载运动模块)
作用:给 SD 模型加「会动的能力」(运动模块 .safetensors)。
参数:model_name 选运动模型(如 mm_sd_v15_v2)
连法:MODEL(从 Checkpoint)→ 输入 → 输出:带运动的 MODEL
2. AnimateDiff Settings(运动参数)
作用:设定视频帧数、帧率、运动强度。
关键参数
total_frames:总帧数(16–32,太长会崩)
fps:8–12
motion_scale:运动幅度(0.5 = 小动,1.0 = 正常,1.5 = 大动)
连法:输出 settings → AnimateDiff Sampler
3. AnimateDiff Sampler(文生视频核心)
作用:带运动地生成一帧帧潜空间(LATENT 序列)。
参数:和 KSampler 一样(steps=25、cfg=8、sampler=dpmpp_2m)
标准文生视频流程
Load Checkpoint → MODEL、CLIP、VAE
Load AnimateDiff Model → 给 MODEL 加运动
CLIP Text Encode(正 / 负提示词)
Empty Latent Image(512×768)
AnimateDiff Settings(24 帧、12fps、motion_scale=1)
AnimateDiff Sampler → 输出 LATENT 序列
VAE Decode → IMAGE 序列
Video Combine → MP4
4. AnimateDiffSlidingWindow(长视频)
作用:超过 32 帧时,用「滑动窗口」防止显存爆炸、画面崩坏。
用法:AnimateDiff Sampler → 这个节点 → VAE Decode
三、SVD(Stable Video Diffusion:图生视频强)
1. SVDLoader(加载 SVD 模型)
作用:加载 SVD 专用视频模型(SVD/SVD-XT)。
输出:svd_model
2. SVD_img2vid_Conditioning(图生视频条件)
作用:把一张参考图变成视频的「初始帧」。
关键参数
motion_bucket_id:运动强度(127 = 中等,越高动越大)
fps:8–12
连法:Load Image(参考图)→ 输入 → 输出:positive、negative、latent
3. VideoLinearCFGGuidance(SVD 专用 CFG)
作用:让提示词在视频全程更稳定,减少闪烁。
4. SVD Sampler(图生视频核心)
流程:参考图 → SVD Conditioning → SVD Sampler → VAE Decode → Video Combine
四、Wan2.7(最新、质量最高:12G+ 显存)
1. Load Checkpoint (Wan)
作用:加载 Wan2.7 官方视频大模型。
2. Empty Latent Video
作用:直接创建「视频潜空间」(含帧数)。
参数:width=1280、height=720、length=24(帧数)
3. Wan Text Encode
作用:编码提示词,支持分段落提示词(比如前 8 帧 A、中间 8 帧 B、最后 8 帧 C)。
4. Wan Chunked I2V Sampler(分块图生视频)
作用:长视频自动分块,支持每段不同提示词,质量极高。
五、视频控制(防闪烁、稳画面、控动作)
1. ControlNet Preprocessor (Video Frame)
作用:对每一帧做 ControlNet 预处理(OpenPose/Canny/Depth)。
用法:VIDEO 帧序列 → 预处理 → ControlNet Apply(每一帧都受控)
2. ControlNet Apply(视频版)
作用:让视频全程姿势 / 线条 / 深度一致,不崩坏。
3. Latent Interpolate(潜空间插值)
作用:两张图之间平滑过渡,转场丝滑。
用法:图 A 潜空间 → 插值 → 图 B 潜空间 → 生成中间帧
4. Prompt Interpolation(提示词渐变)
作用:从提示词 A 慢慢变成提示词 B(比如「白天」→「夜晚」)。
5. Flicker Remover(去闪烁)
作用:AI 视频通病「闪烁」,用这个节点一键修复。
参数:strength=0.3–0.5(太强会变糊)
六、视频后处理(补帧、高清、加音乐)
1. Video Frame Interpolation(插帧,补流畅)
作用:12fps → 24fps,动作更丝滑(常用模型:RIFE/DAIN)。
2. Ultimate SD Upscale(帧超分)
作用:把每一帧放大(如 512→1024),视频变高清。
用法:生成的 IMAGE 序列 → 超分 → 再合成视频
3. FFmpeg 系列(加音乐、裁剪、转场)
AddAudio:给视频加背景音乐。
VideoTransition:两个视频之间加转场(淡入淡出、擦除)。
MultiCuttingVideo:裁剪视频片段。
七、3 套「直接能用」的视频工作流
✅ 新手首选(AnimateDiff 文生视频,8G 显存)
1.Load Checkpoint(SD1.5/RealisticVision)
2.Load AnimateDiff Model(mm_sd_v15_v2)
3.CLIP Text Encode(正:masterpiece, 1girl, blue hair;负:low quality, blurry)
4.Empty Latent Image(512×768)
5.AnimateDiff Settings(24 帧、12fps、motion_scale=1)
6.AnimateDiff Sampler(steps=25、cfg=8、dpmpp_2m)
7.VAE Decode
8.Video Combine(12fps)
✅ 图生视频(SVD,人物 / 风景动起来)
1.Load Image(参考图)
2.SVDLoader(SVD-XT)
3.SVD_img2vid_Conditioning(motion_bucket_id=127、fps=12)
4.SVD Sampler
5.VAE Decode
6.Video Combine
✅ 高质量长视频(Wan2.7,12G+)
1.Load Checkpoint (Wan)
2.Empty Latent Video(1280×720×24 帧)
3.Wan Text Encode(提示词)
4.Wan Chunked I2V Sampler
5.VAE Decode
6.Video Combine
八、常见坑(新手必看)
视频闪烁严重 → 加 Flicker Remover、降低 CFG(7–8)、用 dpmpp_2m 采样器。
画面崩坏 / 人脸畸形 → 加 ControlNet(OpenPose)、motion_scale 降到 0.8、步数≥25。
显存不够(8G) → 用 AnimateDiff、分辨率 512×768、帧数≤24、关闭滑动窗口。
运动太假 / 僵硬 → motion_scale 调到 1.2–1.5、fps=8–10、提示词加「dynamic motion, smooth animation」。
AI咒语
####【豆包】
Q:ComfyUI有API支持第三方调用吗
A:...
ComfyUI 支持通过 API 进行第三方调用,其核心通过内置的 HTTP 服务器提供接口,允许外部程序(如脚本、其他应用)提交工作流、触发生成任务并获取结果。
核心 API 能力说明
1.基础交互方式
ComfyUI 启动时会默认开启一个本地 HTTP 服务器(默认端口 8188),通过发送 HTTP 请求(主要是 POST)与服务器交互,支持提交工作流定义、获取生成状态、下载输出结果等。
2.关键 API 端点
提交工作流任务:POST /prompt
接收一个包含工作流定义的 JSON 数据(即 ComfyUI 中导出的工作流 JSON),触发图像生成任务,返回一个 prompt_id 用于追踪任务状态。示例请求体(简化):
json
{
"prompt": {
"3": {
"class_type": "KSampler",
"inputs": {
"seed": 12345,
"steps": 20,
"cfg": 7.0,
// 其他节点参数...
}
},
// 其他节点定义...
}
}
查询任务状态:GET /history/<prompt_id>通过 prompt_id 查询任务是否完成,返回结果包含生成的图像数据(Base64 编码或文件路径)。
获取输出图像:GET /view?filename=<filename>&type=output直接获取生成的图像文件(需从历史记录中获取 filename)。
第三方调用示例
以 Python 为例,使用 requests 库调用 API 生成图像的基本流程:
python
运行
import requests
import json
# ComfyUI 服务器地址
COMFYUI_URL = "http://localhost:8188"
# 工作流 JSON(可从 ComfyUI 中导出)
workflow = {
# 完整的工作流定义...
}
# 提交任务
response = requests.post(f"{COMFYUI_URL}/prompt", json={"prompt": workflow})
prompt_id = response.json()["prompt_id"]
# 轮询任务状态
import time
while True:
history = requests.get(f"{COMFYUI_URL}/history/{prompt_id}").json()
if prompt_id in history:
# 获取生成的图像数据(Base64)
output_node_id = next(iter(history[prompt_id]["outputs"].keys()))
image_data = history[prompt_id]["outputs"][output_node_id]["images"][0]["data"]
break
time.sleep(1)
# 处理图像数据(如保存为文件)
import base64
from PIL import Image
from io import BytesIO
image = Image.open(BytesIO(base64.b64decode(image_data)))
image.save("output.png")
注意事项
工作流 JSON 格式:API 提交的工作流需严格遵循 ComfyUI 的节点定义格式(可在 ComfyUI 中通过「Save (API Format)」导出)。
版本兼容性:不同版本的 ComfyUI 可能调整 API 细节,建议参考官方文档或 GitHub 仓库 的最新说明。
扩展支持:社区有多个插件(如 ComfyUI-API-Wrapper)可简化 API 调用,提供更友好的接口封装。
通过上述方式,第三方程序可以灵活集成 ComfyUI 的图像生成能力,实现自动化工作流或自定义交互逻辑。
喂饭级教程!ComfyUI本地部署超详细指南
Q:怎么知道节点如何连接?
A:...
先给你一句最关键的:只看颜色 + 左进右出 + 跟着报错走,就能搞定 90% 连接问题。下面分「一眼看懂」「怎么连」「怎么学」三部分讲清楚。
一、先认:端口颜色 = 数据类型(必须同色才能连)

🟣 Model(模型):SD 大模型
🟡 CLIP:文本编码用
🩷 VAE:解码 / 编码图像
🟠 Conditioning:提示词(正负)
🩷 Latent:潜变量(中间图像)
🔵 Image:普通图片
🟢 Mask:蒙版
🟢 Number:数字
一句话:不同颜色坚决连不上,同颜色才能拖线。
二、操作:怎么拖线、怎么断、怎么快速连
1. 基本连接(左进右出)
节点左边是输入(In),右边是输出(Out)
按住右边输出圆点 → 拖到另一个节点左边同色输入圆点 → 松手就连上

断开:右键连线 → 选 Disconnect;或从输入点往外拖一下取消
2. 数量规则(很重要)
输出:1 对多:一个输出可连给多个节点(比如同一个模型给正负提示词)

输入:1 对 1:一个输入只能接一条线,再接会把旧线顶掉
3. 快速找可连接节点(新手神器)
从任意端口往外拖线,能连的节点会亮、不能连的会灰掉

直接选,系统自动帮你插好端口,不用自己猜
三、核心流程:标准文生图是怎么连的(记这个就够)
1 Load Checkpoint(加载模型)
输出:MODEL(紫)、CLIP(黄)、VAE(粉)
2 CLIP Text Encode(Positive)
输入:CLIP(黄)
输出:CONDITIONING(橙)→ 连 KSampler positive
3 CLIP Text Encode(Negative)
输入:CLIP(黄)
输出:CONDITIONING(橙)→ 连 KSampler negative
4 Empty Latent Image(设置尺寸)
输出:LATENT(粉)→ 连 KSampler latent_image
5 KSampler(采样出图)
输入:MODEL、positive、negative、latent_image
输出:LATENT(粉)→ 连 VAE Decode
6 VAE Decode(解码成图)
输入:LATENT、VAE
输出:IMAGE(蓝)→ 连 Preview / Save Image
7 Preview Image / Save Image(看结果 / 保存)
图示意(文字版):
plaintext
Checkpoint ── MODEL → KSampler
── CLIP → 正/负 CLIP Text Encode ── CONDITIONING → KSampler
── VAE → VAE Decode
Empty Latent ── LATENT → KSampler ── LATENT → VAE Decode ── IMAGE → Preview/Save
四、新手怎么快速学会「谁连谁」
1. 先抄现成工作流(最快)
社区随便下一个文生图 / 图生图工作流(.json)
拖进 ComfyUI,顺着线看颜色和流向,对照上面标准流程理解
改一改参数、换个模型,看会不会报错、结果怎么变
2. 看报错信息(最准)
连错会直接红字提示,比如:
TypeError: Cannot connect ... → 颜色 / 类型不对
Multiple links to input → 一个输入连了多个输出
报错会告诉你哪个节点、哪个端口错了,直接改就行
3. 记住几个高频固定配对
CLIP → CLIP Text Encode → KSampler(positive/negative)
Checkpoint → KSampler(model)
Empty Latent → KSampler(latent_image)
KSampler(latent)→ VAE Decode → Image
五、给你一个极简练习步骤(10 分钟上手)
1 拖入:Load Checkpoint、2×CLIP Text Encode、Empty Latent、KSampler、VAE Decode、Preview Image
2 按颜色 + 左进右出,照着标准流程连一遍
3 点 Queue Prompt,能跑出图就成功
4 故意连错一个(比如橙→紫),看报错,加深印象
using System;
using System.IO;
using System.Net.Http;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Windows.Forms;
namespace CallComfyUI
{
public class ComfyUIClient
{
public string serverUrl = "http://127.0.0.1:8188";
private string clientId = Guid.NewGuid().ToString();
private HttpClient httpClient;
public ComfyUIClient()
{
httpClient = new HttpClient();
}
public async Task<string> QueuePrompt(object workflow)
{
object obj = new
{
client_id = clientId,
prompt = workflow
};
string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage resp = await httpClient.PostAsync(serverUrl + "/prompt", content);
string result = await resp.Content.ReadAsStringAsync();
JObject data = JObject.Parse(result);
return (string)data["prompt_id"];
}
public async void WatchWebSocketProgress(string promptId, Action<string> onProgress)
{
ClientWebSocket ws = new ClientWebSocket();
string wsUrl = "ws://127.0.0.1:8188/ws?client_id=" + clientId;
try
{
await ws.ConnectAsync(new Uri(wsUrl), CancellationToken.None);
byte[] buffer = new byte[4096];
while (ws.State == WebSocketState.Open)
{
try
{
var result = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
if (result.MessageType != WebSocketMessageType.Text) continue;
string json = Encoding.UTF8.GetString(buffer, 0, result.Count);
JObject msg = JObject.Parse(json);
string msgType = (string)msg["type"];
JObject dataObj = msg["data"] as JObject;
if (dataObj == null) continue;
JToken pidToken = dataObj["prompt_id"];
if (pidToken == null || pidToken.ToString() != promptId) continue;
if (msgType == "progress")
{
int v = (int)dataObj["value"];
int m = (int)dataObj["max"];
onProgress("进度:" + v + "/" + m);
}
}
catch
{
break;
}
}
}
catch
{
}
finally
{
ws.Dispose();
}
}
public async Task<bool> WaitForTaskComplete(string promptId, Action<string> onStatus, int interval = 1000)
{
while (true)
{
try
{
string url = serverUrl + "/history/" + promptId;
string json = await httpClient.GetStringAsync(url);
JObject history = JObject.Parse(json);
if (history != null && history[promptId] != null)
{
return true;
}
}
catch { }
onStatus("等待任务执行中...");
await Task.Delay(interval);
}
}
public async Task<JObject> GetHistory(string promptId)
{
string url = serverUrl + "/history/" + promptId;
string json = await httpClient.GetStringAsync(url);
return JObject.Parse(json);
}
public async Task<byte[]> GetImage(string filename)
{
string url = serverUrl + "/view?filename=" + filename;
return await httpClient.GetByteArrayAsync(url);
}
}
public static class ComfyUIRunner
{
public static async void Run(Label statusLabel, PictureBox pictureBox)
{
try
{
SetLabel(statusLabel, "加载工作流...");
ComfyUIClient client = new ComfyUIClient();
string jsonText = File.ReadAllText("createpic.json");
JObject workflow = JObject.Parse(jsonText);
JObject node3 = (JObject)workflow["3"];
JObject inputs3 = (JObject)node3["inputs"];
inputs3["seed"] = 123456;
inputs3["steps"] = 28;
inputs3["cfg"] = 9;
JObject node4 = (JObject)workflow["4"];
JObject inputs4 = (JObject)node4["inputs"];
inputs4["ckpt_name"] = "anything-v5-PrtRE.safetensors";
JObject node5 = (JObject)workflow["5"];
JObject inputs5 = (JObject)node5["inputs"];
inputs5["width"] = 512;
inputs5["height"] = 512;
JObject node6 = (JObject)workflow["6"];
JObject inputs6 = (JObject)node6["inputs"];
inputs6["text"] = "一位穿着汉服的漂亮女孩,超写实电影感";//beautiful scenery nature glass bottle landscape, purple galaxy bottle";
JObject node7 = (JObject)workflow["7"];
JObject inputs7 = (JObject)node7["inputs"];
inputs7["text"] = "卡通风格";// "text, watermark";
SetLabel(statusLabel, "提交任务...");
string promptId = await client.QueuePrompt(workflow);
SetLabel(statusLabel, "任务ID:" + promptId);
client.WatchWebSocketProgress(promptId, msg => SetLabel(statusLabel, msg));
bool ok = await client.WaitForTaskComplete(promptId, msg => SetLabel(statusLabel, msg));
if (!ok)
{
SetLabel(statusLabel, "任务失败");
return;
}
SetLabel(statusLabel, "任务完成,获取图片...");
JObject history = await client.GetHistory(promptId);
JObject promptHistory = (JObject)history[promptId];
JObject outputs = (JObject)promptHistory["outputs"];
foreach (JProperty prop in outputs.Properties())
{
JObject node = (JObject)outputs[prop.Name];
JArray images = (JArray)node["images"];
if (images != null && images.Count > 0)
{
string filename = (string)images[0]["filename"];
byte[] data = await client.GetImage(filename);
using (MemoryStream ms = new MemoryStream(data))
{
SetImage(pictureBox, System.Drawing.Image.FromStream(ms));
}
File.WriteAllBytes("output.png", data);
SetLabel(statusLabel, "✅ 生成完成!");
break;
}
}
}
catch (Exception ex)
{
SetLabel(statusLabel, "错误:" + ex.Message);
}
}
private static void SetLabel(Label label, string text)
{
if (label.InvokeRequired)
label.Invoke(new Action(() => label.Text = text));
else
label.Text = text;
}
private static void SetImage(PictureBox pb, System.Drawing.Image img)
{
if (pb.InvokeRequired)
pb.Invoke(new Action(() => pb.Image = img));
else
pb.Image = img;
}
}
}
调用:
ComfyUIRunner.Run(this.lblStatus, this.pictureBox1);
一、自己加简易 Token 验证(本地 API 授权)
给秋叶包加一个简单 Token 校验(最实用):
进入 ComfyUI 目录,编辑 server.py
找到 def routes(self): 附近,加一个校验:
python
运行
# 自定义 API Token
API_TOKEN = "my_secret_token_123"
@app.before_request
def before_request():
if request.path.startswith("/api/"):
token = request.headers.get("X-API-Key")
if token != API_TOKEN:
return {"error": "Unauthorized"}, 401
保存,重启 ComfyUI
调用时在 Header 带:
plaintext
X-API-Key: my_secret_token_123
这样只有带正确 Token 才能访问 API,最适合程序调用。
二、公网安全暴露(反向代理 + 鉴权)
如果要把秋叶包放到公网,推荐用 Nginx + BasicAuth / JWT,不直接开放 8188。
Nginx 配置示例(BasicAuth)
nginx
server {
listen 443 ssl;
server_name your.domain.com;
ssl_certificate fullchain.pem;
ssl_certificate_key privkey.pem;
location / {
proxy_pass http://127.0.0.1:8188;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 账号密码
auth_basic "ComfyUI Auth";
auth_basic_user_file /etc/nginx/.htpasswd;
}
}
生成密码文件:htpasswd -c /etc/nginx/.htpasswd admin
好处:8188 不对外,鉴权、SSL、WSS 都由 Nginx 处理。
公网安全暴露(反向代理 + 鉴权) 根据给的例子如何访问
我给你最简单、最安全、秋叶 ComfyUI 2.8.14 实测可用的一套:
公网暴露 + 账号密码鉴权 + 加密 HTTPS + 绝对安全
你照着复制就能用,我把访问方式也一起给你。
一、最终你会得到
公网地址:https://你的域名.com
访问时必须输入账号密码才能进 ComfyUI
API 调用也必须带鉴权,否则 401 拒绝
全程加密,非常安全
二、你只需要 2 个东西
一个域名(几块钱一年)
内网穿透 / 公网 IP(cpolar、natfrp、阿里云、自家宽带都行)
三、我给你 最简单可直接用的 Nginx 配置(复制即可)
1. nginx.conf 完整配置(带账号密码登录)
server {
listen 80;
server_name 你的域名.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name 你的域名.com;
# SSL 证书(你申请的免费证书)
ssl_certificate cert/fullchain.pem;
ssl_certificate_key cert/privkey.pem;
# 基础安全配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 👇 这里开启账号密码访问
auth_basic "ComfyUI Login";
auth_basic_user_file C:/nginx/conf/.htpasswd;
# 代理到本地 ComfyUI
location / {
proxy_pass http://127.0.0.1:8188;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
四、创建账号密码(关键)在 nginx/conf 目录下新建一个文件 .htpasswd
内容格式:plaintext
admin:密码
例如:plaintext
test:123456
五、启动 Nginx 后你访问 ComfyUI 的方式:
方式 1:浏览器访问(网页)打开:plaintexthttps://你的域名.com
会自动弹出账号密码输入框
输入你设置的账号密码 → 进入 ComfyUI方式
2:API 访问(带鉴权)ComfyUI 的所有 API 都需要账号密码才能调用。
访问格式:plaintext
https://admin:123456@你的域名.com/api/prompt
或者在 Header 里带:
plaintext
Authorization: Basic YWRtaW46MTIzNDU2
六、最简单的公网访问示例(你直接复制)
假设:
域名:abc.com
账号:admin
密码:123456
网页访问
plaintext
https://abc.com
弹出登录框 → 输入 admin / 123456
API 访问
plaintext
https://admin:123456@abc.com/api/prompt
CURL 调用bash运行curl -u admin:123456 https://abc.com/api/prompt
七、这样做的好处(非常安全)
公网无法直接访问 8188
必须账号密码才能进
HTTPS 加密,不会被劫持
防止别人偷跑你的显卡
适合远程调用、团队共享、公网 API
上一篇:大模型本地化部署相关技术收集
下一篇:AI协助编程工具使用详解