SSD Nodes Learn Hosting plans →
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-08-27

علت قطع شدن مداوم n8n روی VPS و راه حل آن

اگر n8n شما مدام آفلاین می‌شود، لزوماً با یک مشکل روبرو نیستید. یاد بگیرید چگونه خطاهای OOM Kill، حلقه‌های restart، مشکلات WebSocket و توقف زمان‌بندی‌ها را از هم تشخیص دهید.

چرا n8n مدام آفلاین می‌شود: چهار خرابی، یک نشانه

عبارت «n8n مدام آفلاین می‌شود» یک جمله است که چهار خرابی متفاوت را پوشش می‌دهد و هر کدام به راه‌حل متفاوتی نیاز دارد. ویرایشگر در حالی که container به‌طور عادی در حال اجراست، بنر قطع اتصال را نشان می‌دهد. container خودبه‌خود restart می‌شود. هسته سیستم‌عامل (kernel)، پردازش Node.js را به دلیل مصرف بیش از حد حافظه می‌کشد (kill می‌کند). یا اینکه هیچ مشکلی در پردازش وجود ندارد و یک workflow فعال، هرگز اجرا نمی‌شود. اگر تنظیمات اشتباهی را تغییر دهید، آخر هفته خود را صرف حل مشکلی خواهید کرد که اصلاً وجود نداشته است.

بنابراین پیش از دست زدن به هر پیکربندی، مشخص کنید با کدام خرابی مواجه هستید. n8n به عنوان یک پردازش واحد Node.js، معمولاً درون یک Docker container و پشت یک reverse proxy که TLS (امنیت لایه انتقال) را مدیریت می‌کند، اجرا می‌شود. هر یک از این لایه‌ها به شیوه خاص خود دچار مشکل می‌شوند و مرورگر همه آن‌ها را با یک پیام مشابه گزارش می‌دهد.

عیب‌یابی به این ترتیب

این دستورات را روی VPS (سرور مجازی) اجرا کنید و مقادیری که سیستم خودتان نمایش می‌دهد را بخوانید. آن‌ها را با اعداد موجود در انجمن‌های گفتگو مقایسه نکنید. مقادیر مهم در اینجا، وضعیت سرور شما را توصیف می‌کنند، نه سرور شخص دیگری را.

docker ps -a --filter name=n8n
docker logs --tail 200 --timestamps n8n
docker inspect n8n | grep -iE 'Status|Running|RestartCount|OOMKilled|ExitCode'
docker stats --no-stream

ستون STATUS از خروجی docker ps -a نشان می‌دهد که کانتینر چه مدت در وضعیت فعلی خود بوده است. این مقدار را با لحظه‌ای که مشکل شما شروع شده مقایسه کنید. اگر کانتینر از مدت‌ها قبل از ظاهر شدن بنر خطا بالا بوده است، پس n8n هرگز آفلاین نشده است. چیزی که دچار اختلال شده، ارتباط بین مرورگر شما و بک‌اند است که همان مسیر websocket است و در بخش بعدی به آن پرداخته می‌شود.

RestartCount نشان می‌دهد که Docker چند بار این کانتینر را ری‌استارت کرده است. عدد را یادداشت کنید، یک دقیقه صبر کنید و دوباره آن را بخوانید. عددی که با گذشت زمان افزایش می‌یابد، نشان‌دهنده یک حلقه ری‌استارت (restart loop) است و خطوط لاگ درست قبل از هر ری‌استارت، دلیل آن را در خود دارند.

OOMKilled یک پرچم (flag) درست یا نادرست است. مقدار True به این معنی است که هسته لینوکس فرآیند را به دلیل عبور از محدودیت حافظه متوقف کرده است؛ این محدودیت می‌تواند مربوط به خود کانتینر یا کل ماشین باشد. همین یک فیلد، تفاوت بین یک توقف ناشی از کمبود حافظه (memory kill) و سایر انواع خروج را مشخص می‌کند، به همین دلیل است که پیش از هر حدسی باید آن را بررسی کنید.

ExitCode نشان‌دهنده آخرین کد خروج کانتینر شماست. نیازی نیست معنای هر کد را حفظ کنید. کد خود را بخوانید و سپس انتهای docker logs را در همان بازه زمانی بررسی کنید. انتهای لاگ و پرچم کمبود حافظه در کنار هم به شما می‌گویند چه اتفاقی افتاده است؛ تکیه بر هر کدام از آن‌ها به‌تنهایی می‌تواند شما را گمراه کند.

docker stats میزان مصرف لحظه‌ای حافظه را در کنار محدودیت اعمال‌شده نشان می‌دهد. بگذارید این دستور در یک ترمینال دوم در حال اجرا بماند، سپس workflowای که باعث خرابی می‌شود را اجرا کنید و ببینید در لحظه وقوع خطا، این عدد چه تغییری می‌کند.


بنر قطع اتصال معمولاً مربوط به reverse proxy شماست

ویرایشگر n8n یک اتصال طولانی‌مدت (long-lived) با backend برقرار نگه می‌دارد تا بتواند پیشرفت اجرا را به‌صورت stream روی canvas نمایش دهد. به‌طور پیش‌فرض، این اتصال یک WebSocket است که توسط N8N_PUSH_BACKEND انتخاب می‌شود و مقدار پیش‌فرض آن websocket است. یک WebSocket به‌عنوان یک درخواست HTTP معمولی شروع می‌شود که شامل هدرهای Connection: Upgrade و Upgrade: websocket است. سرور پاسخ 101 Switching Protocols را برمی‌گرداند و از آن لحظه به بعد، هر دو طرف از همان سوکت TCP برای تبادل داده در هر دو جهت استفاده می‌کنند.

دو عامل باعث اختلال در این فرآیند می‌شوند که هر دو مربوط به proxy هستند، نه n8n. یا proxy از پروتکل HTTP/1.0 در سمت upstream استفاده می‌کند یا هدرهای upgrade را حذف می‌کند؛ در نتیجه ارتقا (upgrade) هرگز انجام نمی‌شود و ویرایشگر مدام در حال تلاش برای اتصال مجدد است. یا ارتقا با موفقیت انجام می‌شود اما proxy بعداً سوکت را به دلیل عدم فعالیت می‌بندد، زیرا یک WebSocket بدون پیام، دقیقاً مانند یک اتصال idle به نظر می‌رسد. در هر دو حالت، container سالم است. نمایش این بنر به این معناست که مرورگر به شما اطلاع می‌دهد که کانال ارتباطی خود را از دست داده است.

پیش از هر تغییری، این موضوع را در مرورگر تأیید کنید. ابزارهای توسعه‌دهنده (developer tools) را باز کنید، به تب Network بروید، فیلتر را روی WS تنظیم کنید و ویرایشگر را reload کنید. درخواست push باید به 101 Switching Protocols برسد و باز بماند. درخواست pushای که یک کد وضعیت (status code) معمولی برمی‌گرداند یا هر چند ثانیه یک‌بار دوباره ظاهر می‌شود، نشان‌دهنده وجود مشکل در proxy است.

تنظیمات nginx برای حفظ اتصال ویرایشگر

nginx تا زمانی که از آن نخواهید، درخواست‌های upgrade را ارسال نمی‌کند. proxy_pass به‌صورت پیش‌فرض با پروتکل HTTP/1.0 با backend صحبت می‌کند و Connection و Upgrade هدرهای hop-by-hop هستند که nginx در مسیر انتقال آن‌ها را حذف می‌کند. شما باید هر دو را دوباره اضافه کنید. بلوک map باید در context http قرار گیرد، نه داخل server. اگر بخش‌های دیگر بلوک server در ادامه برای شما ناآشنا است، بررسی خط‌به‌خط یک بلوک server در nginx توضیح می‌دهد که هر دستور چه کاری انجام می‌دهد.

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
server {
    listen 443 ssl;
    http2 on;
    server_name n8n.example.com;

    location / {
        proxy_pass http://127.0.0.1:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_buffering off;
    }
}

proxy_read_timeout خطی است که معمولاً فراموش می‌شود. مقدار پیش‌فرض آن 60 ثانیه است و برای WebSocket ارتقایافته نیز اعمال می‌شود؛ بنابراین اگر تب ویرایشگر روی یک instance خلوت باز بماند، حدود یک دقیقه پس از آخرین پیام، اتصال خود را از دست می‌دهد. افزایش این مقدار، مشکل بنری که هنگام بازگشت به تب بازشده مشاهده می‌کنید را برطرف می‌کند.

sudo nginx -t && sudo systemctl reload nginx
sudo nginx -T | grep -iE 'proxy_http_version|upgrade|proxy_read_timeout'

nginx -T کل پیکربندی در حال اجرا را به‌جای یک فایل واحد چاپ می‌کند، بنابراین ثابت می‌کند که تغییرات شما واقعاً بارگذاری شده‌اند. پیکربندی‌ای که در فایلی قرار دارد که هیچ خط include آن را فراخوانی نمی‌کند، دلیل اصلی این است که چرا یک اصلاح صحیح، بی‌اثر به نظر می‌رسد.

سپس به n8n اطلاع دهید که پشت یک proxy قرار دارد، زیرا این برنامه URLها را بر اساس این مقادیر می‌سازد.

environment:
  - N8N_HOST=n8n.example.com
  - N8N_PROTOCOL=https
  - N8N_PORT=5678
  - N8N_PROXY_HOPS=1
  - N8N_WEBHOOK_URL=https://n8n.example.com/

مقدار پیش‌فرض N8N_PROXY_HOPS برابر با 0 است، به این معنی که n8n آدرس متصل‌شونده را به‌عنوان آدرس کلاینت در نظر می‌گیرد و X-Forwarded-For را نادیده می‌گیرد. آن را روی تعداد proxyهای موجود در جلوی container تنظیم کنید. تا اوت 2026، N8N_WEBHOOK_URL نام فعلی است و WEBHOOK_URL قدیمی‌تر همچنان کار می‌کند، اگرچه هنگام راه‌اندازی هشدار deprecation نمایش می‌دهد.

Traefik درخواست‌های WebSocket را هدایت می‌کند، اما آن‌ها را با timeout مواجه می‌سازد

Traefik درخواست ارتقای WebSocket را بدون نیاز به middleware یا برچسب‌های اضافی هدایت می‌کند؛ بنابراین کاربری که با این خطا مواجه می‌شود، معمولاً با یک timeout روبروست، نه فقدان header. تنظیمات مربوط به این مورد در entryPoint قرار دارند. از اوت 2026 در Traefik نسخه v3، مقدار پیش‌فرض برای idleTimeout برابر با 180 ثانیه و برای readTimeout برابر با 60 ثانیه است.

entryPoints:
  websecure:
    address: ":443"
    transport:
      respondingTimeouts:
        readTimeout: 0
        idleTimeout: 3600s

Caddy به‌طور خودکار ارتقا را در reverse_proxy مدیریت می‌کند و نیازی به دستورالعمل خاصی برای آن ندارد. اگر به دلیل مدیریت توسط شخص ثالث، امکان تغییر proxy را ندارید، کانال push را با N8N_PUSH_BACKEND=sse تغییر دهید. پروتکل SSE (رویدادهای ارسالی از سمت سرور) یک پاسخ HTTP معمولی است که باز نگه داشته می‌شود؛ بنابراین از proxyهایی که ارتقا را نمی‌پذیرند عبور می‌کند، هرچند یک idle timeout تهاجمی همچنان می‌تواند آن را قطع کند. انتخاب خودِ proxy یک تصمیم مجزا است و مقایسه nginx، Caddy و Traefik هزینه‌های عملیاتی هرکدام را بررسی می‌کند.

زمانی که container واقعاً در حال restart شدن است

اگر RestartCount افزایش می‌یابد، یعنی container با خطا مواجه شده و Docker در حال راه‌اندازی مجدد آن است. زمان‌بندی‌های لاگ را با هر restart تطبیق دهید و آنچه بلافاصله پیش از آن رخ داده است را بخوانید. چهار علت تقریباً تمام این موارد را پوشش می‌دهند: خطای پیکربندی که مانع از شروع به کار می‌شود، دیتابیسی که n8n به آن دسترسی ندارد، crash کردن پس از اجرا، و کشته شدن توسط سیستم به دلیل کمبود حافظه (OOM kill).

با volume شروع کنید، زیرا مجوزهای دسترسی (permissions) عامل پنهانی هستند. image رسمی با کاربر بدون دسترسی ویژه node اجرا می‌شود و داده‌های خود را در /home/node/.n8n نگه می‌دارد. یک bind mount که توسط root ایجاد شده باشد، برای آن کاربر قابل نوشتن نیست؛ بنابراین پردازش هر بار در لحظه شروع متوقف می‌شود و سیاست restart، این مشکل را در یک حلقه پنهان می‌کند.

docker compose config
docker run --rm -it --entrypoint sh docker.n8n.io/n8nio/n8n -c 'id'
docker exec n8n ls -ld /home/node/.n8n

استفاده از یک named volume این مشکل را به‌طور کامل برطرف می‌کند، زیرا Docker آن را با مالکیت صحیح ایجاد می‌کند. اگر به bind mount نیاز دارید، با دستور chown مالکیت دایرکتوری میزبان را به شناسه عددی کاربری که در دستور اول چاپ شده است، تغییر دهید. درک نگاشت مالکیت بین میزبان و container یک بار برای همیشه مفید است و توضیح PUID و PGID بررسی می‌کند که این imageها چگونه تصمیم می‌گیرند چه کسی فایل‌ها را بنویسد.

کشته شدن فرآیند به دلیل کمبود حافظه که شبیه به کرش است

دو سقف حافظه مجزا برای فرآیند n8n وجود دارد که رفتارهای متفاوتی در هنگام خطا نشان می‌دهند. محدودیت گروه کنترل (cgroup) کانتینر توسط هسته سیستم‌عامل اعمال می‌شود: اگر از آن عبور کنید، فرآیند بلافاصله کشته می‌شود، بدون اینکه فرصتی برای نوشتن چیزی داشته باشد و OOMKilled مقدار true را برمی‌گرداند. سقف حافظه V8 در داخل Node.js اعمال می‌شود: اگر از آن عبور کنید، Node یک خطای heap همراه با stack trace ایجاد کرده و خودبه‌خود خارج می‌شود، بنابراین OOMKilled مقدار false را برمی‌گرداند. از دید مرورگر، این دو مورد یکسان به نظر می‌رسند. اما از دید docker inspect، آن‌ها تنها یک فیلد با هم فاصله دارند.

سقف حافظه heap در Node را پایین‌تر از محدودیت کانتینر تنظیم کنید. اگر سقف heap بالاتر از محدودیت کانتینر باشد، V8 به تخصیص حافظه فراتر از نقطه‌ای که هسته مداخله می‌کند ادامه می‌دهد؛ در نتیجه، garbage collector هرگز به محدودیت خود نمی‌رسد و شما همیشه با سخت‌ترین نوع شکست مواجه می‌شوید که هیچ لاگی برای خواندن باقی نمی‌گذارد.

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    environment:
      - NODE_OPTIONS=--max-old-space-size=<MiB, below the container limit>
    deploy:
      resources:
        limits:
          memory: <your container limit>

هر دو عدد را بر اساس منابع واقعی VPS خود انتخاب کنید و فضایی را برای دیتابیس، پروکسی و سیستم‌عامل خالی بگذارید. docker stats --no-stream میزان استفاده فعلی را در کنار محدودیت اعمال‌شده چاپ می‌کند، بنابراین می‌توانید بررسی کنید که محدودیتی که نوشتید همان محدودیتی است که Docker اعمال کرده است. نحوه اعمال محدودیت‌های حافظه در Compose توضیح می‌دهد که وقتی چندین تنظیمات وجود دارد، کدام کلید اولویت پیدا می‌کند.

داده‌های اجرا همان چیزی است که زیر پای شما رشد می‌کند

یک اجرای واحد، خروجی تمام گره‌ها را در حین انجام کار نگه می‌دارد و n8n سپس آن داده‌ها را ذخیره می‌کند. این موضوع دو پیامد دارد. اوج مصرف حافظه در یک اجرا توسط بزرگ‌ترین دسته‌ای از داده‌ها تعیین می‌شود که از آن عبور می‌دهید؛ بنابراین، گردش‌کاری که ده هزار ردیف را به‌طور هم‌زمان پردازش می‌کند، برنامه‌ای متفاوت از همان گردش‌کار است که در هر بار دویست ردیف را مدیریت می‌کند. همچنین، نسخه ذخیره‌شده تا زمانی که چیزی آن را حذف نکند، به رشد خود ادامه می‌دهد.

پاک‌سازی (Pruning) مشکل دوم را حل می‌کند. از اوت 2026، تنظیمات پیش‌فرض به این صورت است که پاک‌سازی فعال است، EXECUTIONS_DATA_MAX_AGE روی 336 ساعت (14 روز) و EXECUTIONS_DATA_PRUNE_MAX_COUNT روی 10000 تنظیم شده است. این مقادیر برای یک VPS کوچک که از SQLite استفاده می‌کند سخاوتمندانه هستند؛ جایی که یک فایل همه چیز را در خود نگه می‌دارد و همان فرآیندی که ویرایشگر را سرویس‌دهی می‌کند، باید آن را بخواند و بنویسد.

environment:
  - EXECUTIONS_DATA_PRUNE=true
  - EXECUTIONS_DATA_MAX_AGE=72
  - EXECUTIONS_DATA_PRUNE_MAX_COUNT=1000
  - EXECUTIONS_DATA_SAVE_ON_SUCCESS=none
  - EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=false

EXECUTIONS_DATA_SAVE_ON_SUCCESS=none تنظیمات تهاجمی است. این گزینه اجراهای ناموفق را برای عیب‌یابی نگه می‌دارد و اجراهای موفق را حذف می‌کند. این تصمیم را آگاهانه بگیرید، زیرا گردش‌کاری که خروجی اشتباه تولید کرده اما خطایی ایجاد نکرده است، در این حالت چیزی برای بررسی باقی نمی‌گذارد. پاک‌سازی همچنین ابتدا ردیف‌ها را به‌عنوان حذف‌شده علامت‌گذاری می‌کند و در مرحله‌ای بعدی آن‌ها را پاک می‌کند، و از آنجا که SQLite صفحات آزادشده را به‌جای بازگرداندن به سیستم‌عامل، دوباره استفاده می‌کند، حجم فایل روی دیسک بلافاصله پس از تغییر تنظیمات کاهش نمی‌یابد.

برای کاهش اوج مصرف به‌جای مجموع داده‌های ذخیره‌شده، در هر اجرا داده‌های کمتری جابه‌جا کنید. کارهای بزرگ را به زیر-گردش‌کارهایی تقسیم کنید که نتایج کوچکی را به والد بازمی‌گردانند، با استفاده از گره Loop Over Items دسته‌بندی کنید و کل مجموعه‌داده‌ها را از گره Code دور نگه دارید.

فایل‌های باینری نباید در حافظه جابه‌جا شوند

N8N_DEFAULT_BINARY_DATA_MODE به‌صورت پیش‌فرض روی default تنظیم شده است که داده‌های باینری را در حافظهٔ پردازش در حال اجرا نگه می‌دارد. هر فایلی که یک نود دانلود می‌کند و هر نسخه‌ای که به نود بعدی تحویل داده می‌شود، تا پایان اجرا در آنجا باقی می‌ماند. یک گردش‌کار که چند پیوست بزرگ را دریافت می‌کند، می‌تواند پردازش را از محدودیتی عبور دهد که کارهای معمولی JSON هرگز به آن نزدیک نمی‌شوند؛ به همین دلیل است که کرش کردن برنامه نه بر اساس زمان، بلکه پس از یک گردش‌کار خاص رخ می‌دهد.

environment:
  - N8N_DEFAULT_BINARY_DATA_MODE=filesystem

با استفاده از filesystem، داده‌های باینری در مسیر N8N_BINARY_DATA_STORAGE_PATH نوشته می‌شوند که به‌طور پیش‌فرض در پوشهٔ کاربری n8n قرار دارد و بنابراین روی همان volume سایر داده‌ها ذخیره می‌شود. پیش از تغییر این تنظیم، بررسی کنید که volume فضای کافی داشته باشد. N8N_PAYLOAD_SIZE_MAX حداکثر اندازهٔ payload وب‌هوک ورودی را بر حسب MiB (مبی‌بایت) تعیین می‌کند و مقدار پیش‌فرض آن 16 است. افزایش این مقدار اجازه می‌دهد درخواست‌های بزرگ‌تری وارد شوند، که این کار هزینه‌ای از نظر مصرف حافظه است که شما آگاهانه می‌پذیرید.

هر سرویس دیگری که روی سرور اجرا می‌شود، برای استفاده از RAM با این پردازش رقابت می‌کند. اگر خطاهای OOM (خروج از حافظه) دقیقاً پس از افزودن یک کانتینر دیتابیس شروع شده‌اند، اجرای دیتابیس در Docker یا روی سیستم‌عامل میزبان همان مبادله‌ای است که اکنون در حال انجام آن هستید.

سیاست راه‌اندازی مجدد و بازگشت پس از reboot

کانتینری که هیچ سیاست راه‌اندازی مجددی ندارد، پس از خروج و همچنین پس از reboot شدن میزبان، متوقف باقی می‌ماند. restart: unless-stopped آن را در هر دو حالت بازمی‌گرداند، در حالی که همچنان به کانتینری که به‌صورت دستی متوقف کرده‌اید، احترام می‌گذارد. restart: always حتی کانتینری را که عمداً متوقف کرده‌اید، پس از راه‌اندازی مجدد Docker دوباره اجرا می‌کند.

سرویس n8n یک endpoint سلامت ارائه می‌دهد که با N8N_ENDPOINT_HEALTH نام‌گذاری شده و مقدار پیش‌فرض آن healthz است. ابتدا آن را از روی میزبان بررسی کنید تا مطمئن شوید مسیر در نمونه (instance) شما درست است.

curl -fsS http://127.0.0.1:5678/healthz
docker exec n8n which wget curl
sudo systemctl is-enabled docker

یک healthcheck به‌تنهایی چیزی را restart نمی‌کند. Compose کانتینر را در وضعیت unhealthy علامت‌گذاری کرده و در همان‌جا متوقف می‌شود؛ بنابراین برای اینکه healthcheck تأثیری داشته باشد، به یک سیاست راه‌اندازی مجدد یا یک ناظر خارجی در کنار آن نیاز است. نوشتن یک healthcheck که واقعاً عمل کند و راه‌اندازی مجدد stack پس از reboot هر دو بخش این موضوع را پوشش می‌دهند.

گردش‌کاری که اجرا نمی‌شود در حالی که n8n سالم است

این مورد نه بنری نمایش می‌دهد و نه باعث راه‌اندازی مجدد می‌شود. کانتینر در حال اجراست، ویرایشگر کار می‌کند، اما اجرای مورد انتظار شما در لیست executions دیده نمی‌شود. چهار دلیل عمده برای این اتفاق وجود دارد:

  • گردش‌کار فعال (Active) نیست. یک Schedule Trigger فقط در مسیر production اجرا می‌شود، بنابراین تست کردن آن در محیط canvas هیچ زمان‌بندی‌ای را فعال نمی‌کند.
  • منطقه زمانی (timezone) با منطقه شما متفاوت است. مقدار پیش‌فرض GENERIC_TIMEZONE برابر با America/New_York است، بنابراین زمان‌بندی تنظیم‌شده برای 09:00 در همان منطقه اجرا می‌شود تا زمانی که GENERIC_TIMEZONE و TZ را روی منطقه زمانی خود تنظیم کنید.
  • زمان‌های از دست رفته (downtime) بعداً جبران نمی‌شوند. تریگرها هنگام شروع به کار n8n ثبت می‌شوند، بنابراین زمان‌بندی‌ای که در حین راه‌اندازی مجدد کانتینر سررسید شده باشد، با تأخیر اجرا نمی‌شود. اجرای بعدی در اولین زمان سررسید پس از بالا آمدن سیستم خواهد بود.
  • گردش‌کار برای شما غیرفعال شده است. گزینه N8N_WORKFLOW_AUTODEACTIVATION_ENABLED به‌صورت پیش‌فرض خاموش است و وقتی روشن باشد، گردش‌کاری که مدام کرش می‌کند از حالت انتشار خارج (unpublished) می‌شود؛ پس از آن، وضعیت آن دقیقاً مشابه گردش‌کاری به نظر می‌رسد که هیچ‌کس آن را فعال نکرده است.

لیست executions را باز کرده و آن را بر اساس گردش‌کار مورد نظر فیلتر کنید. وجود یک ورودی که با خطا مواجه شده، نشان‌دهنده مشکل در خود گردش‌کار است. اگر خطا با کد 429 در ارتباط با سرویس دیگری باشد که روی همان سرور میزبانی می‌کنید، محدودیت مربوط به آن سرویس است نه n8n، و راهنمای رفع خطای 429 در SearXNG نشان می‌دهد که چگونه محدودکننده نرخ (rate limiter) آن سرویس را از مسدود شدن IP سرور توسط موتورهای جستجو تشخیص دهید. اگر هیچ ورودی‌ای ثبت نشده باشد، مشکل از تریگر است و باید چهار دلیل ذکر شده در بالا را بررسی کنید.

اولین تغییرات مورد نیاز

  1. پیش از ویرایش هر فایلی، STATUS، RestartCount و OOMKilled را در کانتینر خود مطالعه کنید.
  2. اگر کانتینر هرگز از دسترس خارج نشده است، هدرهای ارتقای پروکسی (proxy upgrade headers) و مهلت زمانی بیکاری (idle timeout) را اصلاح کنید.
  3. اگر OOMKilled برابر با true است، یک محدودیت کانتینر که آگاهانه انتخاب کرده‌اید تعیین کنید، سقف حافظه heap در Node را پایین‌تر از آن قرار دهید و داده‌های باینری را به filesystem تغییر دهید.
  4. اگر هیچ موردی فعال نشد، بررسی کنید که گردش کار (workflow) فعال باشد و منطقه زمانی (timezone) نمونه با منطقه زمانی شما مطابقت داشته باشد.

بخش عمده‌ای از این موارد، پیکربندی‌هایی هستند که پس از یک نصب موفق، یک‌بار تنظیم می‌شوند و دیگر نیازی به تغییر ندارند. اگر هنوز در حال انجام مراحل نصب هستید، راهنمای نصب n8n روی Docker با HTTPS همان پایه‌ای است که این تنظیمات به آن تعلق دارند.

FAQ

چرا ویرایشگر n8n با وجود در حال اجرا بودن کانتینر، بنر «اتصال قطع شد» (connection lost) را نشان می‌دهد؟

ویرایشگر برای استریم کردن پیشرفت اجرا، یک اتصال WebSocket باز نگه می‌دارد. اگر reverse proxy شما هدرهای Connection: Upgrade و Upgrade: websocket را ارسال نکند، یا از پروتکل HTTP/1.1 در سمت upstream استفاده نکند، عملیات ارتقای اتصال (upgrade) هرگز کامل نمی‌شود و مرورگر دائماً در حال تلاش برای اتصال مجدد خواهد بود، در حالی که n8n در وضعیت سالم قرار دارد. در nginx شما به proxy_http_version 1.1 به همراه هر دو خط proxy_set_header نیاز دارید، و همچنین باید proxy_read_timeout را روی مقداری بیشتر از 60 ثانیه تنظیم کنید تا تب‌های غیرفعال قطع نشوند. پیکربندی در حال اجرا را با sudo nginx -T بررسی کنید، نه فایلی که ویرایش کرده‌اید.

چگونه می‌توانم تفاوت بین کشته شدن به دلیل کمبود حافظه (OOM) و کرش معمولی را تشخیص دهم؟

دستور docker inspect n8n | grep -iE 'OOMKilled|ExitCode|RestartCount' را اجرا کرده و مقدار فلگ OOMKilled را بخوانید. مقدار True به این معنی است که هسته سیستم‌عامل (kernel) فرآیند را به دلیل عبور از محدودیت حافظه کشته است و در لاگ کانتینر چیزی مفیدی نخواهید یافت، زیرا فرآیند فرصتی برای نوشتن نداشته است. مقدار False، همراه با یک خطای heap و stack trace در انتهای docker logs، به این معنی است که Node.js به سقف حافظه V8 خود رسیده و خودش خارج شده است. مقدار NODE_OPTIONS=--max-old-space-size را کمتر از محدودیت کانتینر خود تنظیم کنید تا با خطای دوم مواجه شوید، چرا که این خطا شواهدی از خود باقی می‌گذارد.

آیا پاک‌سازی داده‌های اجرا (pruning) بلافاصله فضای دیسک را آزاد می‌کند؟

خیر. EXECUTIONS_DATA_PRUNE اجراهای قدیمی را برای حذف علامت‌گذاری می‌کند و یک فرآیند در زمان‌بندی تعیین‌شده توسط EXECUTIONS_DATA_PRUNE_HARD_DELETE_INTERVAL آن‌ها را حذف می‌کند. در SQLite، فایل دیتابیس به جای بازگرداندن فضا به سیستم‌فایل، صفحات آزاد شده را مجدداً استفاده می‌کند، بنابراین حجم فایل روی دیسک مدتی پس از حذف ردیف‌ها ثابت می‌ماند. مقادیر EXECUTIONS_DATA_MAX_AGE و EXECUTIONS_DATA_PRUNE_MAX_COUNT را متناسب با سرور خود تنظیم کنید و سپس به جای بررسی فوری، روز بعد وضعیت را چک کنید.

چرا ورک‌فلوهای زمان‌بندی شده من در حین ری‌استارت شدن n8n اجرا نشدند؟

n8n تریگرها را هنگام شروع فرآیند ثبت می‌کند و زمان‌بندی‌هایی که در زمان خاموش بودن سرور سررسید شده‌اند را دوباره اجرا نمی‌کند. بنابراین، یک حلقه ری‌استارت باعث سکوت می‌شود و نه اجرای انبوه کارهای عقب‌مانده؛ و اجرای بعدی در اولین زمان سررسید پس از بالا آمدن سیستم انجام خواهد شد. اگر به اجراهایی نیاز دارید که نباید از دست بروند، ورک‌فلو را از طریق یک فراخوان خارجی که به یک webhook متصل است هدایت کنید تا منطق تلاش مجدد (retry) خارج از n8n قرار بگیرد.

آیا healthcheck در صورت عدم پاسخ‌گویی n8n، آن را ری‌استارت می‌کند؟

به تنهایی خیر. یک healthcheck در Compose فقط وضعیت کانتینر را به عنوان سالم یا ناسالم علامت‌گذاری می‌کند. ری‌استارت کردن وظیفه سیاست ری‌استارت (restart policy) است، بنابراین restart: unless-stopped همان چیزی است که کانتینر را پس از خروج دوباره بالا می‌آورد و همچنین پس از ری‌استارت شدن میزبان (host)، تا زمانی که سرویس Docker فعال باشد، آن را بازمی‌گرداند. این موضوع را با sudo systemctl is-enabled docker تأیید کنید. برای اقدام خاص روی وضعیت ناسالم، به یک ناظر (watcher) خارج از Docker نیاز دارید که وضعیت را بخواند و سرویس را ری‌استارت کند.