ComfyUI بلا واجهة رسومية: شغّله كخدمة، واستخدمه من أي مكان

تاريخ النشر
11 يوليو 2026
تاريخ التحديث
11 يوليو 2026
بقلم
جاكوب لويد — كُتب بمساعدة الذكاء الاصطناعي بعد إنجاز المشروع
مدة القراءة
قراءة 2 دقيقة

بعبارة مبسطة: حاسوب توليد الصور لدي يشغّل ComfyUI طوال الوقت في الخلفية، بلا شاشة وبلا أي شخص مسجّل دخوله إلى سطح مكتب. أستطيع تشغيله، أو التحقق من حالته، أو طلب صورة منه بأمر سطر واحد، وأستطيع فتح واجهته الكاملة من حاسوبي المحمول أو هاتفي عبر اتصال خاص مشفّر. إضافة صغيرة بنيتها تضمن أن كل تدفق عمل أحفظه من أي جهاز يصل إلى ذلك الحاسوب نفسه، حتى لا يتشتت شيء.

في المقال السابق جعلت ComfyUI + Z-Image Turbo يولّدان صورة بدقة 1024 بكسل في نحو 27 ثانية على حاسوب AMD صغير. هذا هو الجزء التالي: تحويل ذلك التثبيت إلى جهاز دائم التشغيل — بلا جلسة سطح مكتب، وبلا مراقبة طرفية — يستطيع أي جهاز في المنزل استخدامه، بينما يبقى كل ما يُنتَج وكل تدفق عمل يُحفَظ على ذلك الجهاز نفسه.

خلاصة سريعة

  • ما هو: ComfyUI يعمل بلا واجهة رسومية تحت خدمة مستخدم systemd، تتحكم فيه واجهة سطر أوامر صغيرة، ويُشغَّل عبر سكربتات باستخدام واجهة HTTP البرمجية، ويُوصَل إليه من أجهزة أخرى عبر شبكة VPN شبكية بـHTTPS.
  • التكلفة: مجانية. مستوى شبكة VPN اللازم لهذا (Tailscale الشخصي) مجاني أيضًا.
  • ما تحتاجه: تثبيت ComfyUI يعمل، وأمسية تقريبًا من الوقت.
  • ما تحصل عليه في النهاية: comfyctl generate "..." من أي شل، والواجهة الكاملة على حاسوبك المحمول أو هاتفك، ومكتبة تدفقات عمل تعيش في مجلد واحد على الخادم بغض النظر عن الجهاز الذي حفظت منه.

ما تحصل عليه في النهاية

يوميًا، "استخدام صندوق الصور" يبدو كواحد من ثلاثة أشياء، لا يتطلب أي منها الجلوس أمامه:

comfyctl status     # server health + systemd state + newest output file
comfyctl generate "a foggy harbor at dawn, cinematic"
comfyctl logs 100

أو سكربت على جهاز آخر يرسل أمرًا (POST) إلى واجهة HTTP البرمجية، أو الواجهة الكاملة لمخطط العُقد مفتوحة في تبويب متصفح على حاسوبي المحمول في الطرف الآخر من المنزل — عبر HTTPS، ومن خلال شبكة VPN، مع وصول الحفظ إلى قرص الخادم.

لماذا بلا واجهة رسومية

واجهة الويب هي وسيلتك لـتصميم تدفق عمل. لكنها وسيلة سيئة جدًا لـتشغيله للمرة المئتين. بمجرد ضبط تدفق العمل، ما تريده فعليًا هو جهاز: صندوق دائم التشغيل، دائم الجاهزية، يجيب طلبات أي جهة تسأله — أمر شل من سطر واحد، مهمة cron، روبوت دردشة يحتاج صورة رمزية جديدة في الساعة 3 فجرًا.

"بلا واجهة رسومية" هنا لا تعني "بلا واجهة إطلاقًا." الخادم ليس له جلسة سطح مكتب ولا متصفح خاص به؛ الواجهة لا تزال موجودة، تُقدَّم عبر 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

ذلك السطر الأخير هو الجزء الخاص بالتشغيل بلا واجهة رسومية الذي يفوّته كثيرون: بدون تفعيل الاستمرارية (lingering)، تتوقف وحدات المستخدم عند انتهاء آخر جلسة لك — وهو ما يعني "فورًا" على جهاز بلا واجهة رسومية. يحافظ EnvironmentFile على المنفذ وأعلام التشغيل في مكان واحد قابل للتعديل (comfy.env)، حتى تستطيع أدوات أخرى قراءة نفس القيمة بدلًا من تثبيت 8188 داخل الكود.

سكربت تحكم على طراز comfyctl

systemctl الخام يعمل، لكن غلاف رقيق يجعل الجهاز يبدو كمنتج. غلافي هو نحو 100 سطر من bash باسم comfyctl:

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 تجيب، لا أن العملية موجودة فقط. curl -sf http://127.0.0.1:$PORT/system_stats في حلقة بمهلة 60 ثانية. قول systemd إن الحالة "active" يعني فقط أن Python بدأ التشغيل؛ خادم النموذج لا يكون جاهزًا حتى يجيب عبر HTTP.
  • يقرأ المنفذ من نفس ملف البيئة الذي تستخدمه الخدمة، حتى لا يؤدي تغيير المنفذ في مكان واحد إلى تعطيل الأداة.
  • generate يشغّل الخادم تلقائيًا. إذا فشل فحص السلامة، يشغّل الوحدة، وينتظر السلامة، ثم يرسل الطلب. لا يحتاج المستدعي أبدًا لمعرفة ما إذا كان الجهاز مستيقظًا.
  • status يطبع أحدث ملف في output/ — إجابة سؤال "هل نجح توليدي الأخير فعليًا" دون فتح أي شيء.

تشغيل واجهة HTTP البرمجية من السكربتات

كل ما تفعله الواجهة يمر عبر نفس واجهة HTTP البرمجية، وحلقة العمل الأساسية هي ثلاث نقاط نهاية (endpoints). تدفق العمل هو مجرد JSON (يُصدَّر عبر Save (API format) في الواجهة)؛ يحمّله سكربت، ويستبدل الأمر (prompt) وبذرة (seed) جديدة، ثم:

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: مكتبة تدفقات عملك تعيش على الجهاز

إليك المشكلة التي ظهرت في الأسبوع الأول من الاستخدام عن بُعد. ميزة Export الأصلية في ComfyUI تحفظ JSON الخاص بتدفق العمل عبر آلية التنزيل في المتصفح — إلى أي جهاز تتصفح منه. استخدم الواجهة من ثلاثة أجهزة، وستجد مكتبة تدفقات عملك مبعثرة عبر ثلاثة مجلدات تنزيلات، لا واحد منها هو الجهاز الذي يشغّل تدفقات العمل فعليًا.

لذا بنيت عقدة مخصصة صغيرة ("Workbench") تصحّح اتجاه الجاذبية. إنها إضافة custom_nodes عادية: يسجّل جانب Python بضعة مسارات على خادم الويب الخاص بـComfyUI نفسه، ويضيف جانب JS تبويبًا في الشريط الجانبي. تؤدي وظيفتين:

1. الحفظ والفتح من مجلد العمل

زر الحفظ في الشريط الجانبي يرسل المخطط الحالي (POST) إلى الإضافة، التي تكتبه في مجلد user/default/workflows القياسي الخاص بـComfyUI على الخادم — باسم ملف مُنظَّف، محصور داخل ذلك المجلد، وكتابة ذرّية (atomic) (ملف مؤقت ثم إعادة تسمية)، ونسخة احتياطية دوّارة .bak.json لأي شيء يُستبدَل. زر الفتح يعرض نفس المجلد، الأحدث أولًا.

النقطة الجوهرية: الواجهة تعمل في متصفح عن بُعد، لكن الحفظ يذهب إلى قرص الخادم المحلي. احفظ من الحاسوب المحمول، وافتح من الهاتف، وشغّل من سكربت — مكتبة واحدة، مجلد واحد، على الجهاز الذي يحمل كرت الشاشة. (في جهازي، ذلك المجلد مربوط رمزيًا بمجلد عادي ~/comfy/workflows، لذا يُنسخ احتياطيًا بسهولة أيضًا.) ولأن الواجهة الأمامية تجري فقط طلبات نسبية للمصدر (origin-relative) إلى الخادم الذي حُمِّلت منه، فإنها تتصرف بنفس الطريقة على localhost وعبر وكيل (proxy) — بلا إعداد خاص لكل جهاز.

2. فحص النماذج الناقصة + تنزيلات بقائمة بيضاء

الألم الآخر للاستخدام عن بُعد: تفتح تدفق عمل ويطلب ملف نموذج لا يملكه الجهاز. تنزيل 12 غيغابايت إلى هاتفك ثم إعادة رفعه أمر خاطئ بوضوح. تفحص الإضافة تدفق العمل المُحمَّل مقابل كل مجلد نماذج مسجَّل، وتعرض ما هو ناقص، وتنزّله من جهة الخادم، مباشرة إلى مجلد models/<folder> الصحيح — يُبَث إلى ملف .part، قابل للاستئناف عبر HTTP Range، مع تحقق اختياري بـsha256، وتقدّم يُدفَع إلى الواجهة عبر websocket.

بما أن جملة "المتصفح يستطيع أن يطلب من الخادم تنزيل عناوين URL عشوائية إلى القرص" مخيفة، فقد أُحيطت بسياج:

  • HTTPS فقط، ويجب أن يطابق اسم المضيف قائمة بيضاء في config.json (مثل huggingface.co، civitai.com، وأحرف بدل مثل *.hf.co) — وتُعاد مراجعة كل قفزة إعادة توجيه مقابل نفس القائمة، لأن "إعادة التوجيه إلى أي مكان" هو الالتفاف الكلاسيكي على القوائم البيضاء.
  • تُختصر أسماء الملفات إلى اسم أساسي مُنظَّف ويجب أن تنتهي بامتداد مدرَج في القائمة البيضاء (.safetensors وما شابه)؛ يجب أن يكون الهدف مجلد نماذج مسجَّلًا — بلا اجتياز مسارات (path traversal).
  • لا تُستبدَل الملفات الموجودة أبدًا، وهناك سقف حجم لكل تنزيل (30 غيغابايت افتراضيًا)، وتُصفّ التنزيلات واحدًا تلو الآخر.

الوصول الآمن عن بُعد: شبكة VPN شبكية + HTTPS

ComfyUI على هذا الجهاز يستمع على 127.0.0.1 فقط — مُثبَّت في الكود، لا عَلَمًا (flag). ليس له صفحة تسجيل دخول، لذا يجب ألا يُكشَف للإنترنت أبدًا، وبصراحة ولا حتى للشبكة المحلية الخام. الحل النظيف هو شبكة VPN شبكية مثل Tailscale: يحصل كل جهاز على عنوان خاص مشفَّر، ولا شيء يمكن الوصول إليه من خارج حسابك، وميزة serve فيها تعمل كوكيل عكسي محلي لـHTTPS:

tailscale serve --bg --https=8443 http://127.0.0.1:8188

الآن يقدّم https://<اسم-جهازك>.<tailnet الخاص بك>.ts.net:8443 الواجهة الكاملة، بشهادة TLS حقيقية (تُصدَر تلقائيًا)، لأجهزتك فقط. لا يزال ComfyUI نفسه لا يسمع إلا من localhost — الوكيل هو الباب الوحيد.

HTTPS ليس لباقة اختيارية هنا. تفرض المتصفحات قيودًا متزايدة (الحافظة، وبعض سلوك worker/websocket) على HTTP العادي من مصادر ليست localhost، وأنت ترسل أوامرك وصورك عبر الشبكة. تمنحك شبكة VPN الشبكية شهادة حقيقية دون امتلاك نطاق أو فتح منفذ. ملاحظة عملية واحدة: اتصل باستخدام اسم DNS الخاص بالجهاز، لا عنوان IP الخام لشبكة VPN — تُصدَر شهادة TLS للاسم، لذا سيفشل عنوان IP في فحص الشهادة.

مطبّات

  • أخطاء 403 التي تحدث فقط عن بُعد هي فحوصات Origin، لا مصادقة. تتحقق وسيطة خادم ComfyUI من Origin/Host وما شابه على الطلبات التي تغيّر الحالة؛ بعض إعدادات الوكيل تمرّر رؤوسًا لا تطابق ما يتوقعه (واجهت هذا بالضبط عند ربط أداة أخرى — خطأ 403 قائم على Sec-Fetch-Site). أصلح الرؤوس المُمرَّرة من الوكيل، أو قصر إعدادات CORS في ComfyUI (--enable-cors-header) على مصدرك الموثوق الوحيد — لا تستخدم * أبدًا.
  • استخدم اسم مضيف VPN، لا عنوان IP. HTTPS عبر شبكة VPN الشبكية هو شهادة لكل اسم؛ الوصول إلى العنوان الخام يعطي أخطاء TLS تبدو وكأن الخادم معطَّل.
  • يجب أن تكون واجهات العُقد المخصصة نسبية للمصدر (origin-relative). أي http://127.0.0.1:8188/... مُثبَّت في كود JS لإضافة يعمل على الجهاز نفسه ويتعطل بصمت عبر الوكيل. استخدم api.fetchApi() الخاصة بـComfyUI ومسارات نسبية.
  • يمكن أن تنقطع اتصالات websocket عبر وكيل. أحداث التقدّم تُنقَل عبر websocket؛ خلف وكيل، تموت أحيانًا بصمت. تقوم Workbench باستطلاع (polling) كخطة احتياطية لهذا السبب بالضبط — صمّم مع وضع ذلك في الحسبان.
  • loginctl enable-linger، وإلا فإن "خدمتك" تموت عند تسجيل الخروج.
  • "الوحدة نشطة" لا تعني "الخادم يعمل."
  • أبقِ القائمة البيضاء للتنزيل ضيّقة.
  • لا تقم أبدًا بتوجيه هذا المنفذ إلى الإنترنت. بلا مصادقة + تنفيذ تدفقات عمل عشوائية + (مع أداة تنزيل) كتابة على القرص. شبكة VPN شبكية أو لا شيء.

حيث انتهى المقال الأول بحاسوب يستطيع توليد الصور، ينتهي هذا المقال بشيء أفضل: جهاز هادئ على رف، يستطيع كل جهاز وسكربت أملكه استخدامه — ويحتفظ بكل ما ينتجه في مكان واحد.


← المزيد من الذكاء الاصطناعي والنماذج المحلية