无头模式下的 ComfyUI:将其作为服务运行,随时随地使用
- 发布日期
- 2026年7月11日
- 更新日期
- 2026年9月16日
- 作者
- Jacob Lloyd —— 项目完成后,在 AI 协助下撰写
- 阅读时长
- 约 13 分钟阅读
简单来说: 我的图像生成专用电脑始终在后台运行着 ComfyUI;那台电脑没有连接显示器,也无人登录桌面。我只需输入一条命令就能启动它、查看状态或请求生成图像;还能通过加密的私有连接,从笔记本电脑或手机上访问它的完整界面。我编写的一个小插件能确保我从任何设备保存的工作流都会同步到这台电脑上,这样就不会出现文件散落各处的情况。
更新于2026年9月16日:我不再在自己的电脑上运行这套ComfyUI环境了——现在日常的图像生成任务都是通过远程GPU服务器完成的。下面的配置说明依然有效,如果你也想以无头模式运行ComfyUI的话仍可照做。
在上一篇文章中,我成功让ComfyUI搭配Z-Image Turbo在一台AMD迷你PC上仅用约27秒便生成出1024像素的图像。本文则是后续内容:把这套环境打造成一个全天候运行的服务器——无需桌面会话、也无需人工干预终端操作——家中任何设备都能调用它,而所有生成的图片与保存的工作流也都存储在同一个机器上。
简而言之
最终效果
日常使用中,“使用这台图像生成服务器”通常表现为以下三种情形,这些操作均无需亲自坐在机器前操作:
comfyctl status # server health + systemd state + newest output file
comfyctl generate "a foggy harbor at dawn, cinematic"
comfyctl logs 100
……又或者是其他设备上的脚本通过HTTP API发送提示词;又或者是在家中的笔记本上通过浏览器打开完整的节点图界面——所有通信都经由VPN与HTTPS完成,生成的图像则直接保存到服务器硬盘中。
为何采用无头模式
网页界面最适合用来设计工作流。可一旦需要重复执行同一流程200次,这种方式就变得极为低效。当工作流配置妥当后,我们真正需要的其实是一个“专用设备”:一台始终开机、随时待命且能响应各类请求的机器——无论是简单的终端命令、定时任务,还是凌晨三点需要生成新头像的聊天机器人——这种设备模式同样适用于我之前将聊天机器人部署到公网的做法,同时又能确保底层硬件不会直接暴露在外部。
此处的“无头模式”并非意味着“完全没有用户界面”。该服务器本身确实没有桌面会话与浏览器;但用户界面依旧存在,只是通过HTTP协议提供给其他设备使用。服务器负责实际运算工作,其余设备仅充当显示终端而已。
systemd用户服务
这里的服务配置方式与前文所述一致,故在此简述。systemd的用户级服务文件位于 ~/.config/systemd/user/comfyui.service:
[Unit]
Description=ComfyUI server
After=network-online.target
[Service]
ExecStart=%h/comfy/start-comfyui.sh
WorkingDirectory=%h/comfy/ComfyUI
EnvironmentFile=-%h/comfy/comfy.env
Restart=on-failure
RestartSec=5
TimeoutStartSec=120
[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user enable --now comfyui.service
loginctl enable-linger $USER # keep user services running with nobody logged in
最后一行正是无头模式下容易被忽略的关键点:若未设置相应参数,用户级服务会在最后一个会话结束后自动停止——对于无头服务器而言,这意味着“立刻停止”。EnvironmentFile的作用则是把端口号与启动参数统一存放在一个可编辑的文件中(即 comfy.env),这样其他工具也能读取到相同的值,而无需硬编码端口号8188。
类似comfyctl的控制脚本
直接使用systemctl也可实现管理,但一个轻量级的封装层能让这台服务器更像一个完整的产品。我编写的 comfyctl 脚本仅约100行Bash代码:
comfyctl start # systemctl start + poll /system_stats until healthy
comfyctl stop
comfyctl restart
comfyctl status # health + unit state + newest output PNG
comfyctl generate "<prompt>" [--seed N --steps 8 --width 1024 --out PATH]
comfyctl logs [N] # journalctl --user -u comfyui.service -n N
以下细节使其使用体验更佳而非仅仅简洁易用:
- “健康状态”指API能够正常响应,而非进程仍在运行。脚本会以60秒为时限反复执行
curl -sf http://127.0.0.1:$PORT/system_stats。systemd显示的“active”状态仅代表Python程序已启动;只有模型服务器真正回应HTTP请求才算健康。 - 脚本从与服务相同的环境文件中读取端口号,如此即便更改端口,也不会导致工具无法正常工作。
generate命令会自动启动服务器。若健康检查失败,它会先启动服务单元并等待其恢复健康状态后再提交请求。调用者完全无需知晓服务器是否处于唤醒状态。status命令会显示output/文件夹中最新的文件——这样用户无需打开任何界面就能确认“上一次生成任务是否成功完成”。
通过脚本调用HTTP API
网页界面能做的所有操作本质上都经由同一套HTTP API实现,其核心流程仅涉及三个端点。一个工作流其实就是一段JSON数据(可通过界面的“以API格式保存”选项导出);脚本只需加载该数据、替换提示词与随机种子即可:
import json, time, urllib.request
SERVER = "http://127.0.0.1:8188"
graph = json.load(open("workflow_api.json"))
graph["6"]["inputs"]["text"] = "a foggy harbor at dawn, cinematic" # your prompt node id
# 1. queue it
req = urllib.request.Request(f"{SERVER}/prompt",
data=json.dumps({"prompt": graph}).encode(),
headers={"Content-Type": "application/json"})
pid = json.load(urllib.request.urlopen(req))["prompt_id"]
# 2. poll history until done
while True:
hist = json.load(urllib.request.urlopen(f"{SERVER}/history/{pid}"))
if pid in hist: break
time.sleep(1)
# 3. fetch the image
img = hist[pid]["outputs"]["9"]["images"][0] # your SaveImage node id
url = f"{SERVER}/view?filename={img['filename']}&subfolder={img['subfolder']}&type={img['type']}"
open("result.png", "wb").write(urllib.request.urlopen(url).read())
整个实现仅依赖标准库——无需任何ComfyUI专用客户端包,也无需API密钥。这正是 comfyctl generate 背后的运作机制;它使得该服务器真正成为基础设施的一部分:只要具备发送HTTP请求的能力,任何程序都能生成图像。
Workbench插件:让工作流库集中存储于服务器上
在远程使用的最初一周里,我遇到了这样一个问题:ComfyUI自带的“导出”功能会通过浏览器的下载机制将工作流JSON文件保存到当前正在使用的设备上。若在三台不同设备上操作界面,工作流文件就会分散在三个“下载”文件夹中,而真正执行运算的服务器上反而没有任何相关文件。
于是我自行开发了一个名为“Workbench”的自定义节点。它属于典型的 custom_nodes 插件:Python端代码会在ComfyUI自身的Web服务器上注册若干路由;前端JS代码则新增一个侧边栏标签。该插件主要完成两项功能:
1. 工作文件夹的保存/打开功能
侧边栏中的“保存”按钮会将当前工作流以 POST 请求的形式发送给插件,后者会将其写入 ComfyUI 的 user/default/workflows 文件夹中——该文件夹位于服务器端。系统会对文件名进行清理处理,确保其仅存在于该文件夹内;保存过程采用原子性写入方式(先创建临时文件再重命名)。此外,系统还会生成一个 .bak.json 备份文件以记录被覆盖的原内容。“打开”功能则会列出同一文件夹下的所有工作流,并按最新时间排序。
关键点在于:用户界面运行在远程浏览器中,但保存操作实际上是写入服务器端的本地磁盘。你可以在笔记本电脑上保存工作流,随后在手机上打开;甚至可以通过脚本来执行相关操作——所有这些操作都依赖于同一个库以及位于装有 GPU 的机器上的那个文件夹。(在我的电脑上,该文件夹被设置了符号链接,指向普通的 ~/comfy/workflows 目录,因此备份起来也极为方便。)由于前端仅向其加载来源的服务器发送相对路径请求,因此无论是在本地主机还是通过代理访问,其行为都完全一致——无需针对每个设备单独配置。
2. 缺失模型扫描与允许下载的网址列表
远程使用的另一个难题是:打开一个工作流后,系统却需要某个本地设备并未包含的模型文件。显然,把12GB大小的模型下载到手机上再重新上传是不合理的做法。该插件会对比已加载的工作流与所有已注册的模型文件夹,列出缺失的模型,随后在服务器端直接将其下载至正确的 models/<folder> 目录中——下载过程以流式传输方式写入 .part 文件,支持通过 HTTP Range 功能断点续传;用户还可选择进行 SHA256 校验,下载进度也会通过 WebSocket 实时反馈到用户界面。
由于“浏览器能指示服务器从任意网址下载文件并保存到磁盘”这一说法听起来有些危险,因此系统设置了诸多限制:
- 仅允许 HTTPS 连接,且主机名必须符合
config.json中设定的允许列表(例如huggingface.co、civitai.com,以及类似*.hf.co的通配符);每次重定向请求均需重新验证——因为随意重定向正是绕过允许列表的常见手段。 - 文件名需经过清理处理,且必须以允许的扩展名结尾(如
.safetensors等);目标目录也必须是已注册的模型文件夹,禁止路径遍历操作。 - 已有文件绝不会被覆盖;每次下载均有大小限制(默认为30GB),且下载任务按队列依次执行。
安全的远程访问方式:网状 VPN + HTTPS
此设备上的 ComfyUI 仅监听 127.0.0.1 地址——这是硬编码设定,无法通过参数更改。由于它没有登录页面,因此绝不可直接暴露于互联网,甚至不应轻易接入局域网。最佳解决方案便是使用类似 Tailscale 的网状 VPN:每台设备都会获得一个加密的私有地址,除用户账户内的设备外无人能访问;其 serve 功能还能充当本地 HTTPS 反向代理。
tailscale serve --bg --https=8443 http://127.0.0.1:8188
这样一来,https://<your-machine>.<your-tailnet>.ts.net:8443 就能为你的所有设备提供完整的用户界面了;该地址还配有自动生成的真实 TLS 证书。实际上 ComfyUI 本身仍只接收来自本地主机的请求——代理才是唯一的访问入口。
在此场景下 HTTPS 并非可有可无的选项。浏览器对非本地主机来源的纯 HTTP 连接限制日益增多(如剪贴板功能、某些 Web Worker/WebSocket 行为等),而你的提示词与图片数据也需在网络中传输。网状 VPN 不仅能提供真正的 TLS 证书,还无需购买域名或开放端口。一个小提醒:请使用设备的 DNS 名称进行连接,而非其原始 VPN IP——因为证书是基于该名称颁发的,使用 IP 会导致证书校验失败。
注意事项
- 仅在远程访问时出现 403 错误属于源地址验证问题,与认证无关。 ComfyUI 的服务器中间件会对涉及状态变更的请求进行
Origin/Host等字段校验;某些代理设置转发的头部信息可能不符合预期(我在配置另一款工具时就遇到了此类情况——出现了基于Sec-Fetch-Site验证的 403 错误)。解决办法是修正代理的转发头部,或将 ComfyUI 的 CORS 设置限制为唯一可信源地址(使用--enable-cors-header参数),切勿设为*。 - 务必使用 VPN 的主机名而非 IP 地址。 网状 VPN 下的 HTTPS 是基于主机名颁发证书的;若直接使用原始 IP,则会出现看似服务器出问题的 TLS 错误。
- 自定义节点前端代码必须使用相对路径。 插件中的任何硬编码
http://127.0.0.1:8188/...形式路径在本地能正常工作,但经过代理后则会失效。应改用 ComfyUI 提供的api.fetchApi()方法并采用相对路径。 - 通过代理连接时 WebSocket 可能会中断。 下载进度信息正是通过 WebSocket 传输的;在代理环境下它偶尔会无声无息地断开。Workbench 之所以设有轮询机制,正是为了应对此情况——设计系统时也需考虑到这一点。
- 执行
loginctl enable-linger后,你的“服务”才会在用户登出后仍保持运行。 - “服务状态为活跃”并不等同于“服务器已正常运行”。
- 务必严格控制允许下载的网址列表。
- 绝对不可将此设备端口直接转发至互联网。 该设备无身份验证机制、可执行任意工作流,且具备文件写入能力(尤其是配合下载器使用时)。因此唯有网状 VPN 才是安全的选择。
前文描述的是一台“能够”生成图像的计算机,而本文所介绍的则更为理想:一台安静地置于书架上的设备,不仅我所有的终端与脚本都能调用它,还能将生成的所有内容集中保存于同一位置。
相关文章:基于 AMD(ROCm)平台的本地 AI 图像生成:ComfyUI + Z-Image Turbo · 在自有硬件上搭建面向公网的聊天机器人 · StudioForge:取代 LM Studio 的纯 GPU 驱动的 LLM 服务器 · 在迷你电脑上部署小型 AI 代理集群:我的 OpenClaw 解决方案