SSD Nodes Learn Hosting plans →
راهنماها Matt Connorتوسط Matt Connor

مقایسه ابزارهای رسم نمودار self-hosted

بررسی draw.io، Excalidraw و Kroki برای میزبانی شخصی. بدانید کدام ابزار داده‌ها را در مرورگر پردازش می‌کند و کدام یک برای امنیت حریم خصوصی به سرور شما نیاز دارد.

کدام ابزار رسم نمودار self-hosted را باید اجرا کنید؟

ابزارهای رسم نمودار self-hosted در دو قالب ارائه می‌شوند و این قالب از لیست ویژگی‌ها اهمیت بیشتری دارد. draw.io و Excalidraw برنامه‌های مبتنی بر مرورگر هستند: کانتینر، JavaScript را ارائه می‌دهد، مرورگر شما عملیات رسم را انجام می‌دهد و سرور هرگز نمودار را مشاهده نمی‌کند. Kroki دقیقاً برعکس عمل می‌کند. شما متن نمودار را از طریق HTTP برای آن می‌فرستید و آن یک تصویر بازمی‌گرداند، بنابراین هر نمودار از طریق ماشین شما پردازش می‌شود.

اگر به یک ویرایشگر کامل در کنار یک ویکی نیاز دارید، draw.io را اجرا کنید. اگر به یک تخته‌سفید برای طراحی سریع نیاز دارید و می‌پذیرید که هیچ‌چیز خارج از مرورگری که در آن طراحی کرده‌اید ذخیره نمی‌شود، Excalidraw را اجرا کنید. اگر نمودارهای شما متنی هستند که در کنار کدی که توصیف می‌کنند در git قرار دارند، Kroki را اجرا کنید.

آنچه میزبانی شخصی (self-hosting) یک ابزار رسم نمودار واقعاً تغییر می‌دهد

دقیق باشید که کدام بخش‌ها با سرور شما در تعامل هستند، زیرا همین یک نکته تعیین می‌کند که آیا میزبانی شخصی باعث افزایش حریم خصوصی می‌شود یا صرفاً در دسترس بودن را تضمین می‌کند.

  • ابزار draw.io در مرورگر رندر می‌شود. کانتینر شما فقط کد برنامه را سرو می‌کند. فایل نهایی به هر کجا که در ویرایشگر تعیین کنید، ذخیره می‌شود.
  • ابزار Excalidraw در مرورگر رندر می‌شود و صحنه فعلی را در local storage همان مرورگر نگه می‌دارد. هیچ چیزی در سمت سرور نوشته نمی‌شود.
  • ابزار Kroki روی سرور رندر می‌شود. هم منبع نمودار و هم تصویر نهایی، هر دو درون کانتینر شما وجود دارند.

تنها در مورد سوم است که داده‌ها به سخت‌افزاری که کنترل آن را در دست دارید منتقل می‌شوند. در دو مورد اول، میزبانی شخصی باعث کنترل بر دارایی‌ها و تضمین در دسترس بودن می‌شود: کدهای JavaScript از میزبان شما بارگذاری می‌شوند، بنابراین وقتی یک سرویس‌دهنده شخص ثالث دچار قطعی شود، شرایط استفاده خود را تغییر دهد یا از شبکه شما غیرقابل دسترس شود، ویرایشگر همچنان کار می‌کند. این موضوع برای برخی تیم‌ها ارزش واقعی دارد. این ادعایی متفاوت از این است که بگوییم «نمودار هرگز از ساختمان خارج نمی‌شود».

draw.io: یک کانتینر رسمی که هیچ‌چیز را ذخیره نمی‌کند

این پروژه تصویر (image) اختصاصی خود را منتشر می‌کند و راهنمای شروع سریع در فایل README آن تنها یک خط است.

docker run -it --rm --name="draw" -p 8080:8080 -p 8443:8443 jgraph/drawio

این دستور، ویرایشگر را روی تمام آدرس‌های موجود در سرور منتشر می‌کند. در یک VPS، پورت منتشرشده را به loopback محدود کنید و از طریق یک reverse proxy یا SSH tunnel به آن دسترسی پیدا کنید.

docker run -d --name drawio --restart unless-stopped -p 127.0.0.1:8080:8080 jgraph/drawio

پورت http://127.0.0.1:8080/?offline=1&https=0 را از طریق تونل باز کنید. فایل README از ?offline=1 به عنوان «یک قابلیت امنیتی که پشتیبانی از فضای ابری را غیرفعال می‌کند» یاد می‌کند. بدون این گزینه، ویرایشگر گزینه‌های Google Drive، OneDrive و GitHub را به عنوان مقاصد ذخیره‌سازی پیشنهاد می‌دهد که در واقع سرورهای اشخاص ثالث هستند.

محدود کردن به 127.0.0.1 همان چیزی است که باعث می‌شود آن پورت از دسترس اینترنت عمومی خارج بماند. یک دستور -p 8080:8080 ساده توسط ufw فیلتر نمی‌شود، زیرا Docker قوانین iptables اختصاصی خود را پیش از زنجیره‌های مدیریت‌شده توسط ufw قرار می‌دهد؛ بنابراین وضعیت فایروال درست به نظر می‌رسد اما پورت همچنان به درخواست‌های عمومی پاسخ می‌دهد. بخش انتشار Docker بدون عبور از ufw این مکانیزم و راه حل آن را بررسی می‌کند.

به محض اینکه ویرایشگر روی localhost نباشد، دو متغیر محیطی اهمیت پیدا می‌کنند.

services:
  drawio:
    image: jgraph/drawio
    container_name: drawio
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      DRAWIO_SERVER_URL: "https://drawio.example.com/"
      DRAWIO_BASE_URL: "https://drawio.example.com"

اسلش انتهایی (trailing slash) اشتباه تایپی نیست. فایل README متغیر DRAWIO_SERVER_URL را به عنوان «URL استقرار عمومی با یک اسلش در انتها» و DRAWIO_BASE_URL را به عنوان «همان URL بدون اسلش انتهایی» تعریف می‌کند که توسط viewer، lightbox و مسیرهای کد embed استفاده می‌شوند. اگر ویرایشگر را تحت یک زیرمسیر (subpath) مانند https://www.example.com/drawio/ ارائه می‌دهید، هر دو مقدار باید شامل آن زیرمسیر باشند، زیرا برنامه URLهای viewer و embed خود را بر اساس آن‌ها می‌سازد.

ماندگاری (Persistence): هیچ‌چیز باقی نمی‌ماند و این بخشی از طراحی است. هیچ volumeای در آن فایل Compose وجود ندارد زیرا کانتینر هیچ داده‌ای از نمودارها را نگه نمی‌دارد. یک فایل .drawio در واقع XMLای است که ویرایشگر به مرورگر شما تحویل می‌دهد و مقصد ذخیره‌سازی که انتخاب می‌کنید تعیین می‌کند فایل کجا قرار بگیرد: دانلود روی سیستم خودتان یا برنامه‌ای که ویرایشگر را در خود جای داده است. از آن مقصد پشتیبان تهیه کنید. اگر پاسخ یک پوشه روی VPS است، پس چیزی که ارزش محافظت دارد همان پوشه و مدیریت فایلی است که برای دسترسی به آن استفاده می‌کنید، زیرا draw.io هیچ نسخه‌ای از هیچ‌چیز را نگه نمی‌دارد.

چه چیزی همچنان سرور شما را ترک می‌کند. کمتر از گذشته، زیرا خروجی (export) دیگر به هیچ‌جا ارسال نمی‌شود. فایل README اکنون EXPORT_URL و DRAWIO_SELF_CONTAINED را در لیست متغیرهای حذف‌شده قرار داده است که دیگر اثری ندارند. آن‌ها ویرایشگر را به تصویر جداگانه jgraph/export-server هدایت می‌کردند که «به پایان عمر خود رسیده است». نقطه ورود (entrypoint) اکنون window.EXPORT_URL = null را در PreConfig.js می‌نویسد که به ویرایشگر اعلام می‌کند هیچ سرویس خروجی وجود ندارد. در عمل، گزینه Export as > PDF کادر چاپ مرورگر را باز می‌کند، بنابراین گزینه شامل کردن نسخه‌ای از نمودار برای PDF ارائه نمی‌شود و خروجی PNG و JPEG که توسط سرور رندر می‌شد، مخفی شده است. خروجی PNG، JPEG و SVG که در مرورگر رندر می‌شوند همچنان کار می‌کنند. گزینه ENABLE_DRAWIO_PROXY به‌صورت پیش‌فرض خاموش است و یک endpoint به نام /proxy را فعال می‌کند که URLهای تصاویر خارجی را از طرف مرورگر دریافت می‌کند؛ بنابراین مگر اینکه به آن نیاز داشته باشید، آن را خاموش نگه دارید.

Excalidraw: یک بسته ایستا بدون سرور پشتیبان

صفحه رسمی ایمیج، این دستور را ارائه می‌دهد.

docker run --rm -dit --name excalidraw -p 5000:80 excalidraw/excalidraw:latest

پورت منتشرشده را به همان دلیلی که قبلاً ذکر شد، به loopback منتقل کنید.

docker run -d --name excalidraw --restart unless-stopped -p 127.0.0.1:5000:80 excalidraw/excalidraw:latest

درون کانتینر، Nginx یک بسته JavaScript کامپایل‌شده را روی پورت 80 ارائه می‌دهد. حجم ایمیج منتشرشده حدود 41 مگابایت فشرده است (Docker Hub، اکتبر 2026) که نشان می‌دهد محتوای آن چقدر اندک است. هیچ دیتابیس، ذخیره‌ساز نشست (session store) یا دایرکتوری آپلودی وجود ندارد، زیرا چیزی روی سرور برای ذخیره‌سازی نیست.

صفحه ایمیج محدودیت را به‌وضوح بیان می‌کند: "در حال حاضر، میزبانی شخصی یک نمونه (instance) از برنامه، از قابلیت‌های اشتراک‌گذاری یا همکاری پشتیبانی نمی‌کند." دکمه‌ها همچنان در رابط کاربری وجود دارند، بنابراین دانستن دلیل آن ارزشمند است. همکاری زنده (Live collaboration) به یک سرور websocket نیاز دارد که به‌صورت جداگانه با نام excalidraw/excalidraw-room منتشر می‌شود. لینک اشتراک‌گذاری به یک سرویس ذخیره‌سازی برای نگهداری صحنه (scene) رمزنگاری‌شده نیاز دارد. آدرس هر دو در زمان build به عنوان متغیرهای Vite (VITE_APP_WS_SERVER_URL، VITE_APP_BACKEND_V2_GET_URL، VITE_APP_BACKEND_V2_POST_URL) در بسته کامپایل می‌شوند و مقادیر production در مخزن کد، به سرویس‌های میزبانی‌شده توسط خود Excalidraw اشاره دارند. Vite این مقادیر را در طول فرآیند build جایگزین می‌کند، بنابراین آن‌ها به صورت رشته‌های متنی ثابت درون JavaScript قرار می‌گیرند. تنظیم آن‌ها به عنوان متغیرهای محیطی کانتینر (environment variables) هیچ تغییری ایجاد نمی‌کند، زیرا هیچ کدی در زمان اجرا (runtime) آن‌ها را نمی‌خواند. اشاره دادن قابلیت همکاری به سرور room اختصاصی خودتان، مستلزم ساخت (build) فرانت‌اند از روی سورس‌کد با مقادیر شخصی‌سازی‌شده است. پیش از برنامه‌ریزی، وضعیت آن سرور را بررسی کنید: تا اکتبر 2026، آخرین push ایمیج excalidraw/excalidraw-room در Docker Hub مربوط به دسامبر 2023 بوده است.

یک نقاشی واقعاً کجا ذخیره می‌شود. صحنه در local storage مرورگر، روی همان دستگاه و برای همان origin باقی می‌ماند. همان URL را در یک پنجره private باز کنید تا ببینید بوم نقاشی خالی است؛ این سریع‌ترین راه برای اثبات این موضوع به خودتان است. پاک کردن داده‌های سایت، نقاشی را حذف می‌کند و هیچ نسخه سروری برای بازیابی وجود ندارد. بنابراین به کاربران آموزش دهید که از گزینه "Save to..." استفاده کنند و فایل .excalidraw را که یک فایل JSON است، در جایی که از آن بک‌آپ گرفته می‌شود، نگه دارند. یک نمونه اشتراکی، به هر فرد بوم نقاشی خصوصی خودش را می‌دهد. با آن به عنوان یک دفترچه یادداشت شخصی برخورد کنید که اتفاقاً روی سرور میزبانی شده است.

Kroki: نمودارها به عنوان کد، رندر شده روی سرور شما

Kroki یک درگاه HTTP در مقابل چندین رندرکننده است. شما متن را POST می‌کنید و SVG یا PNG تحویل می‌گیرید. Graphviz، PlantUML، D2 و چندین مورد دیگر در image درگاه تعبیه شده‌اند. رندرکننده‌های Mermaid، BPMN و Excalidraw در کانتینرهای جانبی (companion) قرار دارند، بنابراین استفاده از Compose منطقی‌ترین روش برای اجرای آن است. این نمونه‌ای از مستندات Kroki است.

services:
  kroki:
    image: yuzutech/kroki
    depends_on:
      - mermaid
      - bpmn
      - excalidraw
    environment:
      - KROKI_MERMAID_HOST=mermaid
      - KROKI_BPMN_HOST=bpmn
      - KROKI_EXCALIDRAW_HOST=excalidraw
    ports:
      - "8000:8000"
    tmpfs:
      - /tmp:exec
  mermaid:
    image: yuzutech/kroki-mermaid
    expose:
      - "8002"
  bpmn:
    image: yuzutech/kroki-bpmn
    expose:
      - "8003"
  excalidraw:
    image: yuzutech/kroki-excalidraw
    expose:
      - "8004"

expose هیچ پورتی را روی host منتشر نمی‌کند، بنابراین کانتینرهای جانبی فقط از طریق شبکه Compose برای درگاه قابل دسترسی هستند. این دقیقاً همان چیزی است که نیاز دارید. خط درگاه را به "127.0.0.1:8000:8000" تغییر دهید، مگر اینکه ویکی که آن را فراخوانی می‌کند روی host دیگری اجرا شود. اگر قبلاً فایل Compose روی سرور ننوشته‌اید، اجرای Docker Compose روی VPS ساختار فایل و چرخه docker compose up -d را پوشش می‌دهد.

دو تست سلامت (smoke test) را به همین ترتیب اجرا کنید، زیرا به دلایل متفاوتی ممکن است شکست بخورند.

curl -s -X POST http://127.0.0.1:8000/graphviz/svg \
  -H 'Content-Type: text/plain' \
  --data-binary 'digraph G {Hello->World}' | head -c 60

Graphviz داخل درگاه اجرا می‌شود، بنابراین یک سند SVG در اینجا ثابت می‌کند که خود درگاه سالم است. حالا مسیری را که از کانتینرها عبور می‌کند تست کنید.

curl -s -X POST http://127.0.0.1:8000/mermaid/svg \
  -H 'Content-Type: text/plain' \
  --data-binary 'graph TD; A-->B;' | head -c 60

خروجی SVG از دستور دوم ثابت می‌کند که KROKI_MERMAID_HOST به درستی resolve شده و کانتینر جانبی پاسخ داده است. اگر اولی کار می‌کند و دومی خیر، خطا بین دو کانتینر است؛ بنابراین پیش از تغییر در سینتکس نمودار، docker compose logs kroki را مطالعه کنید.

فرم GET، نمودار را در URL انکود می‌کند؛ این همان روشی است که یک ویکی بدون نیاز به هیچ پلاگینی، تصویر را embed می‌کند. مستندات این انکودر را ارائه داده‌اند.

cat hello.dot | python -c "import sys; import base64; import zlib; print(base64.urlsafe_b64encode(zlib.compress(sys.stdin.read().encode('utf-8'), 9)).decode('ascii'))"

در Ubuntu این دستور python: command not found را چاپ می‌کند، زیرا سیستم python3 را ارائه می‌دهد و python بدون نسخه وجود ندارد. از python3 استفاده کنید. خروجی در انتهای URL با فرمت /{diagram-type}/{output-format}/{encoded-diagram} قرار می‌گیرد و هر تگ <img> می‌تواند به آن اشاره کند. یک محدودیت وجود دارد: KROKI_MAX_URI_LENGTH به‌طور پیش‌فرض 4096 بایت است، بنابراین نمودارهای طولانی باید از طریق POST ارسال شوند.

Kroki متنی را که برایش می‌فرستید می‌خواند، بنابراین تنظیمات امنیتی آن اهمیت حیاتی دارند. KROKI_SAFE_MODE به‌طور پیش‌فرض روی SECURE تنظیم شده است که محدودکننده‌ترین سطح از میان سه سطح موجود است و KROKI_PLANTUML_ALLOW_INCLUDE به‌طور پیش‌فرض false است. این مقادیر پیش‌فرض به این دلیل وجود دارند که دستور !include در PlantUML، فایل‌ها و URLها را از دیدگاه رندرکننده می‌خواند. اگر این محدودیت‌ها را در endpointای که برای همه قابل دسترسی است کاهش دهید، در واقع به اینترنت اجازه داده‌اید از طریق کانتینر شما فایل بخواند. آن‌ها را تغییر ندهید مگر اینکه دقیقاً بدانید به چه مسیر includeای نیاز دارید، سپس آن را با KROKI_PLANTUML_INCLUDE_PATH مشخص کنید.

حافظه: کدام‌یک در یک VPS کوچک فشار بیشتری وارد می‌کند

هنگامی که بدانید هر کانتینر چه کاری انجام می‌دهد، ترتیب مصرف منابع قابل پیش‌بینی است.

  • ایمیج Excalidraw یک Nginx است که فایل‌های استاتیک را سرو می‌کند. این مورد در مقایسه با دو مورد دیگر، بسیار کم‌هزینه‌تر است.
  • برنامه draw.io از Tomcat استفاده می‌کند که یک application server جاوا است؛ بنابراین چه کسی در حال رسم باشد و چه نباشد، یک JVM (ماشین مجازی جاوا) را همراه خود دارد.
  • سرویس Kroki نیز یک سرویس جاوا است که برای نصب دستی به صورت یک فایل jar ارائه می‌شود.
  • سرویس جانبی mermaid پرهزینه‌ترین مورد است. فایل Dockerfile آن، Chromium را نصب کرده و PUPPETEER_EXECUTABLE_PATH=/usr/lib/chromium/chrome را تنظیم می‌کند، زیرا Mermaid در یک موتور مرورگر واقعی رندر می‌شود.

بنابراین، اعداد در حالت idle (بیکار) اطلاعات بسیار کمی به شما می‌دهند. عددی که اهمیت دارد، جهش مصرف حافظه هنگام رندر شدن یک نمودار است و KROKI_MERMAID_MAX_CONCURRENCY به‌طور پیش‌فرض روی 6 تنظیم شده است؛ یعنی شش رندر مرورگر می‌توانند هم‌زمان در حال اجرا باشند. به‌جای اعتماد به ارقام منتشرشده، آن را روی سرور خودتان اندازه‌گیری کنید.

docker stats --no-stream
docker system df

ابتدا در حالی که همه چیز در حالت idle است، دستور را اجرا کنید و سپس دوباره در حالی که یک نمودار بزرگ mermaid را در یک حلقه رندر می‌کنید، آن را تکرار نمایید. اگر این جهش مصرف در یک پلن کوچک آزاردهنده است، به‌جای حدس زدن، آن را محدود کنید: تنظیم محدودیت حافظه برای یک سرویس Compose نحو (syntax) این کار و اتفاقی که هنگام رسیدن کانتینر به سقف مجاز رخ می‌دهد را نشان می‌دهد. حذف سرویس جانبی mermaid نیز یک راهکار معتبر است، زیرا gateway همچنان به سرویس‌دهی به تمام رندرهای داخلی خود ادامه می‌دهد.

هیچ‌کدام از این ابزارها مدل کاربری ندارند، پس یکی در مقابل آن‌ها قرار دهید

ابزار draw.io فاقد سیستم حساب کاربری است. Excalidraw نیز حساب کاربری ندارد. Kroki به هر درخواستی که به آن برسد پاسخ می‌دهد. هرگونه ورود به سیستم باید از طریق پروکسی انجام شود.

sudo apt update && sudo apt install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd alice

دستور htpasswd -c فایل را ایجاد کرده و روی فایل موجود بازنویسی می‌کند، بنابراین فقط در اولین مرتبه از -c استفاده کنید و پس از آن دیگر نیازی به آن نیست.

server {
    listen 443 ssl;
    server_name drawio.example.com;

    location / {
        auth_basic "diagrams";
        auth_basic_user_file /etc/nginx/.htpasswd;
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

آن را با sudo nginx -t && sudo systemctl reload nginx اعمال کنید. بخش nginx -t اهمیت ویژه‌ای دارد: بارگذاری مجدد (reload) با یک پیکربندی ناقص باعث می‌شود پیکربندی قبلی همچنان اجرا شود؛ در نتیجه سایت به کار خود ادامه می‌دهد و تغییرات شما اعمال نمی‌شود. پیکربندی reverse proxy، توضیح خط به خط بلوک هدر و مسیرهای گواهی که در این قطعه کد حذف شده‌اند را پوشش می‌دهد.

احراز هویت پایه (Basic authentication) ابزار مناسبی برای Kroki نیست و دلیل آن ارزش بررسی دارد. یک صفحه ویکی، تصویر Kroki را با تگ <img> جای‌گذاری می‌کند. مرورگر کاربر آن URL را به عنوان یک زیرمنبع (subresource) با منشأ متفاوت (cross-origin) فراخوانی می‌کند. مرورگر اعتبارنامه‌های Basic که از قبل برای میزبان Kroki ذخیره شده را ضمیمه می‌کند، اما مرورگرهای امروزی برای تصاویر cross-origin پنجره ورود به سیستم نمایش نمی‌دهند. بنابراین هر کاربری که مستقیماً به میزبان Kroki وارد نشده باشد، با خطای 401 مواجه شده و تمام نمودارهای صفحه را به صورت تصویر شکسته می‌بیند. Kroki را از دسترس اینترنت عمومی خارج کنید. آن را در همان شبکه Docker کانتینر ویکی قرار دهید و اجازه دهید ویکی از طریق نام سرویس به آن دسترسی پیدا کند، بدون اینکه هیچ پورتی روی میزبان منتشر شود. نحوه حل نام سرویس‌ها در شبکه‌های Compose بخشی است که این سناریو را عملی می‌کند.

نمودارهایی که در کنار یک ویکی self-hosted قرار می‌گیرند

این معمول‌ترین دلیلی است که افراد به دنبال چنین راهکارهایی هستند. یک صفحه ویکی به تصویر نیاز دارد و هیچ‌کس نمی‌خواهد آن تصویر، اسکرین‌شاتی از لپ‌تاپ شخصی باشد.

نرم‌افزار BookStack یک قلاب (hook) سطح بالا برای ویرایشگرهای self-hosted دارد. آدرس embed پیش‌فرض آن https://embed.diagrams.net/?embed=1&proto=json&spin=1&configure=1 است و با افزودن یک خط در .env، می‌توانید آن را به کانتینر خود هدایت کنید.

DRAWIO=https://drawio.example.com/?embed=1&proto=json&spin=1&configure=1

رشته پرس‌وجو (query string) را دقیقاً کپی کنید. مستندات BookStack بیان می‌کند که embed=1&proto=json&spin=1 «برای عملکرد یکپارچه‌سازی با BookStack ضروری هستند»، زیرا پروتکل پیام JSON را که دو صفحه برای ارتباط با یکدیگر استفاده می‌کنند، انتخاب می‌کنند. همان صفحه به stealth=1 اشاره می‌کند که «اگر نمی‌خواهید از سرویس‌های خارجی دیگر استفاده کنید» کاربرد دارد؛ این همان گزینه‌ای است که وقتی هدف از self-hosting جلوگیری از تماس‌های خروجی است، باید اضافه کنید. با انجام این تنظیمات، BookStack نقاشی را در فضای ذخیره‌سازی تصویر خود در کنار صفحه ذخیره می‌کند، بنابراین نسخه پشتیبانی که از ویکی تهیه می‌کنید، شامل نسخه پشتیبان نمودارها نیز خواهد بود.

اگر هنوز در انتخاب خودِ ویکی تردید دارید، ابتدا آن را تعیین تکلیف کنید. انتخاب بین BookStack، Wiki.js و Outline تصمیمی است که باید پیش از این بگیرید، زیرا ویکی تعیین می‌کند که نمودار چگونه به صفحه پیوست شود و در نتیجه مشخص می‌کند که کدام‌یک از این ابزارها را باید به آن متصل کنید.

حالت‌های شکست و پیام‌هایی که مشاهده خواهید کرد

ویرایشگر طراحی در BookStack باز می‌شود و بی‌نهایت می‌چرخد. آیکون چرخان (spinner) به دلیل spin=1 منتظر داده‌های نمودار است. با proto=json، ویرایشگر هنگام آماده‌شدن یک رویداد init ارسال می‌کند و انتظار دارد در پاسخ، یک اکشن load حاوی نمودار دریافت کند؛ بنابراین اگر این تبادل کامل نشود، آیکون چرخان باقی می‌ماند. بررسی کنید که embed=1&proto=json&spin=1 در مقدار DRAWIO شما موجود باشد و بخش میزبان (host) غلط املایی نداشته باشد.

قاب ویرایشگر در یک ویکی با پروتکل HTTPS خالی می‌ماند. کنسول مرورگر خطای mixed content را گزارش می‌دهد که در حال بارگذاری http:// درون https:// است. مرورگر قاب را مسدود می‌کند و draw.io هرگز اجرا نمی‌شود. ویرایشگر را از طریق HTTPS ارائه دهید.

سرویس Kroki خطای 413 Request Entity Too Large برمی‌گرداند. این عبارت دقیقاً همان نام‌گذاری nginx برای این خطا است، بنابراین پروکسی اولین مظنون است؛ اما Kroki نیز می‌تواند خطای 413 مخصوص به خود را ارسال کند که در مستندات آن با عنوان Content Too Large شناخته می‌شود. مقدار پیش‌فرض client_max_body_size در nginx برابر با 1 MB است و این همان محدودیتی است که سورس‌های بزرگ PlantUML با آن مواجه می‌شوند، زیرا PlantUML درون gateway رندر می‌شود. مقدار KROKI_MAX_BODY_SIZE در خود Kroki نیز به‌طور پیش‌فرض 1mb است، اما این مورد فقط در کانتینرهای جانبی diagrams.net، Excalidraw و Mermaid وجود دارد؛ بنابراین یک سورس بزرگ Mermaid می‌تواند به هر یک از این دو محدودیت برخورد کند. ابتدا client_max_body_size را افزایش دهید و در صورتی که نمودار از طریق یک کانتینر جانبی عبور می‌کند، KROKI_MAX_BODY_SIZE را نیز در آن کانتینر افزایش دهید.

سرویس Mermaid با شکست مواجه می‌شود در حالی که graphviz کار می‌کند. gateway سالم است اما دسترسی به کانتینر جانبی برقرار نمی‌شود. با استفاده از docker compose ps بررسی کنید که سرویس بالا باشد، سپس چک کنید که KROKI_MERMAID_HOST با نام سرویس مطابقت داشته باشد، زیرا مقدار پیش‌فرض آن 127.0.0.1 است که در داخل کانتینر gateway به معنای خودِ gateway است.

قابلیت همکاری (collaboration) در Excalidraw متصل نمی‌شود. اگر فرانت‌اند را برای سرور اتاق (room server) خودتان ساخته‌اید و آن را پشت nginx قرار داده‌اید، پروکسی باید اتصال را با proxy_set_header Upgrade $http_upgrade; و proxy_set_header Connection "upgrade"; ارتقا دهد. بدون این تنظیمات، هندشیک websocket به عنوان یک درخواست HTTP معمولی پاسخ داده می‌شود و نشست (session) هرگز آغاز نمی‌شود.

بوم (canvas) پس از پاکسازی مرورگر خالی است. صحنه در حافظه محلی (local storage) همان دستگاه بوده و نسخه‌ای روی سرور وجود ندارد. راه‌حل این مشکل یک عادت است تا یک تنظیمات: برای هر چیزی که ارزش نگهداری دارد، فایل .excalidraw را خروجی بگیرید.

FAQ

آیا میزبانی شخصی (self-hosting) نرم‌افزار draw.io، نمودارهای من را خصوصی نگه می‌دارد؟

این کار کد برنامه را روی سرور شما نگه می‌دارد، که با خصوصی نگه داشتن داده‌ها متفاوت است. draw.io در مرورگر شما رندر می‌شود، بنابراین کانتینر هرگز نموداری را در خود ذخیره نمی‌کند. حریم خصوصی در این حالت به محل ذخیره فایل و تماس‌های خروجی که فعال باقی می‌گذارید بستگی دارد. از ?offline=1 برای غیرفعال کردن مقاصد ذخیره‌سازی ابری استفاده کنید و ENABLE_DRAWIO_PROXY را خاموش بگذارید. خروجی گرفتن (Export) نیز چیزی به بیرون نمی‌فرستد: تصویر هیچ سرویس خروجی را پیکربندی نمی‌کند، بنابراین PDF از طریق پنجره چاپ مرورگر تولید می‌شود و DRAWIO_SELF_CONTAINED دیگر هیچ اثری ندارد.

چرا قابلیت همکاری (collaboration) در نسخه self-hosted نرم‌افزار Excalidraw کار نمی‌کند؟

صفحه رسمی ایمیج این نرم‌افزار بیان می‌کند که میزبانی شخصی «از قابلیت‌های اشتراک‌گذاری یا همکاری پشتیبانی نمی‌کند». همکاری زنده (Live collaboration) به سرور وب‌سکت جداگانه excalidraw/excalidraw-room نیاز دارد و لینک‌های اشتراک‌گذاری به یک سرویس ذخیره‌سازی وابسته هستند. آدرس هر دوی این‌ها در زمان build در باندل JavaScript به عنوان متغیرهای Vite مانند VITE_APP_WS_SERVER_URL کامپایل می‌شوند، بنابراین تنظیم متغیر محیطی (environment variable) روی کانتینر در حال اجرا هیچ اثری ندارد. استفاده از سرور اتاق (room server) اختصاصی خودتان به معنای build کردن فرانت‌اند از روی سورس‌کد با مقادیر مورد نظر شماست.

چگونه نمودارهای Mermaid را روی سرور شخصی خود رندر کنم؟

Kroki را به همراه کانتینر جانبی mermaid آن اجرا کنید و KROKI_MERMAID_HOST را روی نام آن سرویس تنظیم نمایید. سپس متن نمودار را به /mermaid/svg به صورت POST ارسال کنید و SVG را از پاسخ دریافت نمایید، یا نمودار را در یک URL به صورت GET کدگذاری کرده و یک تگ <img> را به آن اشاره دهید. کانتینر جانبی، Chromium را از طریق Puppeteer هدایت می‌کند زیرا Mermaid به یک موتور مرورگر نیاز دارد، پس برای حافظه برنامه‌ریزی کنید: KROKI_MERMAID_MAX_CONCURRENCY به‌طور پیش‌فرض 6 رندر همزمان را مدیریت می‌کند.

آیا نیاز دارم که روی این ابزارها رمز عبور بگذارم؟

بله، زیرا هیچ‌کدام از آن‌ها سیستم حساب کاربری ندارند. draw.io و Excalidraw یک ویرایشگر کامل را در اختیار هر کسی که URL را پیدا کند قرار می‌دهند و Kroki هر متنی که به آن ارسال شود را رندر می‌کند. احراز هویت پایه (Basic authentication) در reverse proxy برای این دو ویرایشگر کافی است. برای Kroki، آن را در یک شبکه Docker که با ویکی مشترک است منتشرنشده نگه دارید، زیرا مرورگر کاربر برای یک <img> در مبدأ (origin) دیگر، پنجره ورود نمایش نمی‌دهد؛ بنابراین هر نمودار تعبیه‌شده برای کسی که مستقیماً به Kroki وارد نشده باشد، از کار می‌افتد.

آیا این مقاله مفید بود؟

#diagrams#drawio#excalidraw#mermaid#kroki#docker