في مقال الأدوات شغلنا n8n في Container واحد بقاعدة SQLite، ورأينا أنه يحفظ كل تشغيل ويعيد ما فشل، ورأينا أيضاً أنه عملية واحدة تعمل على نواة واحدة. وهذا الإعداد مناسب للتجربة، ولكنه في الإنتاج يترك عدة مشاكل تنتظرك: قاعدة بيانات في ملف داخل Volume، ومفتاح تشفير لا تعرف أين هو، وعنوان Webhook خاطئ عندما تضعه خلف Reverse Proxy، وكود يكتبه أي مستخدم في عقدة Code ويعمل بجانب بيانات الاعتماد.
وفي هذا الدليل سوف نثبت n8n كما يجب أن يعمل في الإنتاج، ثم نكسره في الأماكن التي تنكسر فيها التثبيتات الحقيقية.
المواضيع في السلسلة:
- أتمتة سير العمل Workflow: متى تكتب كوداً ومتى تستخدم أداة؟
- أدوات أتمتة سير العمل Workflow: n8n وNode-RED وبدائلهما
- تثبيت n8n على سيرفرك للإنتاج بطريقة آمنة (الموضوع الحالي)
- سير عمل حقيقي في n8n: من التذكرة إلى تسليم الجهاز
- وكيل ذكي AI Agent في n8n بنموذج محلي وموافقة بشرية
وسوف نناقش في هذا المقال ما يلي:
- معمارية n8n في وضع الطابور Queue Mode: الرئيسي Main وال Workers وRedis وPostgreSQL ومشغلات الكود Task Runners.
- ملف Docker Compose كامل بإصدارات مثبتة، ومفتاح التشفير، وCaddy أمامه.
- عنوان ال Webhook خلف ال Reverse Proxy، وماذا يحدث إذا نسيته.
- قياس الحمل وتوزيعه على Worker اثنين، واستهلاك الذاكرة الحقيقي.
- النسخ الاحتياطي والاستعادة، وما يحدث إذا فقدت مفتاح التشفير.
- الترقيات، والمستخدمين والدخول الموحد SSO، والتحذيرات الأمنية في 2026 وكيف تتعامل معها.
المعمارية: من يستقبل ومن ينفذ
في الوضع الافتراضي يقوم n8n بكل شيء في عملية واحدة: يعرض المحرر، ويستقبل ال Webhooks، وينفذ سير العمل Workflow. أما في وضع الطابور Queue Mode فيتوزع العمل كما في الصورة التالية:

وفي الصورة أعلاه لاحظ التالي:
- الرئيسي Main: يعرض المحرر وال API، ويستقبل ال Webhooks والمؤقتات، فينشئ التشغيل ولا ينفذه، ويضع رقمه في الطابور Queue.
- Redis: يحمل أرقام التشغيلات Executions المنتظرة، فيأخذ أول Worker متاح الرقم التالي.
- ال Worker: عملية n8n أخرى تقرأ سير العمل Workflow من قاعدة البيانات وتنفذه وتكتب النتيجة، وينفذ كل Worker حتى عشرة تشغيلات معاً افتراضياً، والتوثيق ينصح بألا تقل عن خمسة، لأن عدداً كبيراً من ال Workers بقيمة منخفضة يستنزف اتصالات قاعدة البيانات.
- مشغلات الكود Task Runners: الكود الذي يكتبه المستخدم في عقدة Code يعمل في Container منفصل بجانب كل Worker، وسوف نشرح لماذا في قسم الأمان.
- مفتاح التشفير: يجب أن يكون نفسه في الرئيسي وفي كل Worker، لأن ال Worker هو الذي يفك بيانات الاعتماد عندما ينفذ.
وقد يتساءل البعض: هل أحتاج وضع الطابور Queue Mode لفريق صغير؟ والإجابة أن ما تحتاجه دائماً هو PostgreSQL ومفتاح تشفير محفوظ ومشغلات كود خارجية، أما ال Workers فتحتاجها عندما يبدأ تشغيل ثقيل في إبطاء المحرر أو تأخير ال Webhooks الأخرى. ووضع الطابور Queue Mode نفسه موجود في النسخة المجانية Community، أما تعدد الرئيسي Multi-main لتوفر أعلى للرئيسي فمدفوع، كما في صفحة مقارنة النسخ.
قاعدة البيانات: PostgreSQL وليس SQLite
يستخدم n8n قاعدة SQLite افتراضياً، وهي ملف داخل مجلد البيانات، والتوثيق يذكر صراحة أن وضع الطابور Queue Mode مع SQLite غير مدعوم، فال Workers تحتاج قاعدة واحدة تصل إليها كلها. وبحسب صفحة اختيار قاعدة البيانات يدعم n8n آخر إصدارين من PostgreSQL مع إصدار ثالث للتوافق، أي 17 و18 ومعهما 16 كما في يوليو 2026، والصفحة نفسها تذكر أن النطاق يتغير كل نوفمبر مع إصدارات PostgreSQL. واخترنا 17.11، وقد شرحنا تثبيت PostgreSQL بصلاحيات واضحة في PostgreSQL للفرق، والاستعادة إلى أي لحظة في pgBackRest، فلا نعيدهما هنا.
التثبيت بملف Docker Compose
الملف التالي هو الذي شغلناه في المختبر بالإصدارات n8nio/n8n:2.43.4 وn8nio/runners:2.43.4 وpostgres:17.11 وredis:8.10.2 وcaddy:2.11.7-alpine، وكل الأسرار فيه تأتي من ملف .env بجانبه:
# Lab: n8n 2.43.4 in queue mode: main + 2 workers (each with a task runners sidecar), PostgreSQL 17, Redis, Caddy
name: lab-auto-n8n
x-n8n-env: &n8n-env
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: lab-auto-pg
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: ${PG_PASSWORD}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
EXECUTIONS_MODE: queue
QUEUE_BULL_REDIS_HOST: lab-auto-redis
QUEUE_BULL_REDIS_PASSWORD: ${REDIS_PASSWORD}
QUEUE_HEALTH_CHECK_ACTIVE: "true"
OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS: "true"
N8N_RUNNERS_MODE: external
N8N_RUNNERS_AUTH_TOKEN: ${RUNNERS_TOKEN}
N8N_RUNNERS_BROKER_LISTEN_ADDRESS: 0.0.0.0
N8N_HOST: n8n.localhost
N8N_PROTOCOL: https
N8N_WEBHOOK_URL: ${WEBHOOK_URL}
N8N_PROXY_HOPS: ${PROXY_HOPS}
GENERIC_TIMEZONE: Asia/Riyadh
TZ: Asia/Riyadh
N8N_DIAGNOSTICS_ENABLED: "false"
N8N_PERSONALIZATION_ENABLED: "false"
services:
lab-auto-pg:
image: postgres:17.11
container_name: lab-auto-pg
environment:
POSTGRES_DB: n8n
POSTGRES_USER: n8n
POSTGRES_PASSWORD: ${PG_PASSWORD}
volumes: [lab-auto-pgdata:/var/lib/postgresql/data]
healthcheck: { test: ["CMD-SHELL", "pg_isready -U n8n -d n8n"], interval: 5s, retries: 20 }
lab-auto-redis:
image: redis:8.10.2
container_name: lab-auto-redis
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}", "--appendonly", "yes"]
volumes: [lab-auto-redisdata:/data]
healthcheck: { test: ["CMD-SHELL", "redis-cli -a $$REDIS_PASSWORD --no-auth-warning ping"], interval: 5s, retries: 20 }
environment: { REDIS_PASSWORD: "${REDIS_PASSWORD}" }
lab-auto-n8n:
image: n8nio/n8n:2.43.4
container_name: lab-auto-n8n
environment: *n8n-env
volumes: [lab-auto-n8ndata:/home/node/.n8n]
depends_on:
lab-auto-pg: { condition: service_healthy }
lab-auto-redis: { condition: service_healthy }
lab-auto-worker1:
image: n8nio/n8n:2.43.4
container_name: lab-auto-worker1
command: ["worker", "--concurrency=10"]
environment: *n8n-env
depends_on: [lab-auto-n8n]
lab-auto-runners1:
image: n8nio/runners:2.43.4
container_name: lab-auto-runners1
environment:
N8N_RUNNERS_TASK_BROKER_URI: http://lab-auto-worker1:5679
N8N_RUNNERS_AUTH_TOKEN: ${RUNNERS_TOKEN}
depends_on: [lab-auto-worker1]
lab-auto-worker2:
image: n8nio/n8n:2.43.4
container_name: lab-auto-worker2
command: ["worker", "--concurrency=10"]
environment: *n8n-env
depends_on: [lab-auto-n8n]
lab-auto-runners2:
image: n8nio/runners:2.43.4
container_name: lab-auto-runners2
environment:
N8N_RUNNERS_TASK_BROKER_URI: http://lab-auto-worker2:5679
N8N_RUNNERS_AUTH_TOKEN: ${RUNNERS_TOKEN}
depends_on: [lab-auto-worker2]
lab-auto-caddy:
image: caddy:2.11.7-alpine
container_name: lab-auto-caddy
ports: ["127.0.0.1:8443:443"]
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- lab-auto-caddydata:/data
depends_on: [lab-auto-n8n]
volumes:
lab-auto-pgdata:
lab-auto-redisdata:
lab-auto-n8ndata:
lab-auto-caddydata:
networks:
default:
name: lab-auto-n8n-netوملف .env تولده مرة واحدة كما يلي، ثم تحفظ نسخة منه في مخزن الأسرار لديك قبل أي شيء آخر، والسبب سوف تراه في قسم الاستعادة:
cat > .env <<EOF
PG_PASSWORD=$(openssl rand -hex 16)
REDIS_PASSWORD=$(openssl rand -hex 16)
RUNNERS_TOKEN=$(openssl rand -hex 24)
N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)
WEBHOOK_URL=https://n8n.example.com/
PROXY_HOPS=1
EOF
chmod 600 .env
docker compose up -dوفي الإعداد أعلاه لاحظ التالي:
- البيئة المشتركة
x-n8n-env: الرئيسي وال Workers يأخذون المتغيرات نفسها من مكان واحد، فلا يمكن أن يختلف مفتاح التشفير أو عنوان ال Webhook بينها بالخطأ، وسوف نرى في الاختبار أدناه ماذا يحدث عندما يختلف. N8N_ENCRYPTION_KEY: إذا لم تحدده يولد n8n مفتاحاً عشوائياً في أول تشغيل ويحفظه في ملفconfigداخل مجلد البيانات، كما في توثيق مفتاح التشفير، وهذا يعمل مع Container واحد، ولكنه في وضع الطابور Queue Mode يجب أن يكون متغيراً تعطيه للجميع.EXECUTIONS_MODE: queueومتغيراتQUEUE_BULL_REDIS_*: تفعل وضع الطابور Queue Mode وتربطه بـ Redis، ووضعنا لـ Redis كلمة مرور لأنه افتراضياً يعمل دونها.OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS: حتى التشغيل اليدوي من المحرر يذهب إلى ال Workers، فلا يحتاج الرئيسي مشغلات كود خاصة به.N8N_RUNNERS_MODE: external: عقدة Code تعمل في Containerrunnersمنفصل لكل Worker، ويجب أن يكون إصداره هو إصدار n8n نفسه، كما في توثيق مشغلات الكود Task Runners.- لا يوجد منفذ منشور إلا منفذ Caddy: n8n وPostgreSQL وRedis لا تصل إليها إلا من الشبكة الداخلية، وفي المختبر ربطنا Caddy بالعنوان
127.0.0.1:8443، وفي سيرفر حقيقي يكون 443.
وملف Caddy الذي استخدمناه في المختبر يصدر شهادة من جهة داخلية لأن النطاق n8n.localhost محلي:
n8n.localhost {
tls internal
reverse_proxy lab-auto-n8n:5678
}وعلى سيرفر حقيقي تحذف السطر tls internal وتضع نطاقك، فيصدر Caddy شهادة Let's Encrypt تلقائياً كما شرحنا في تثبيت Caddy.
وعند التشغيل كتب الرئيسي في سجله ما يلي (آخر الأسطر):
Version: 2.43.4
Building workflow dependency index...
Editor is now accessible via:
https://n8n.localhost:8443
Finished building workflow dependency index. Processed 0 draft workflows, 0 published workflows.وكتب كل Worker عدد التشغيلات Executions التي يقبلها معاً، ثم سجل مشغلي الكود Task Runners من Container ال runners:
* Concurrency: 10
* Pool: (default)
* Queue: jobs
Registered runner "launcher-javascript" (c42298a321128899)
Registered runner "launcher-python" (e48d1cbfe547220e) ثم أنشأنا حساب المالك Owner، وهو أول حساب ويملك كل الصلاحيات، فلا تترك المحرر مفتوحاً على الإنترنت قبل إنشائه، لأن أول من يصل إليه يصبح هو المالك.
عنوان ال Webhook خلف ال Reverse Proxy
يبني n8n عناوين ال Webhooks التي يعرضها في المحرر ويسجلها عند الخدمات الخارجية من N8N_PROTOCOL وN8N_HOST وN8N_PORT، أي من المنفذ الذي يعمل عليه داخلياً وهو 5678، بينما يصل إليه العالم على 443 عبر ال Reverse Proxy. لذلك يطلب التوثيق ثلاثة أشياء:
- أن تحدد العنوان العام بالمتغير
N8N_WEBHOOK_URL، وهو الاسم الجديد المتاح من الإصدار 2.30.0، وأصبح الاسم القديمWEBHOOK_URLمهملاً Deprecated من 2.35.0. - أن تضع
N8N_PROXY_HOPS=1عندما يوجد Reverse Proxy واحد أمامه. - أن يمرر آخر Proxy الترويسات
X-Forwarded-ForوX-Forwarded-HostوX-Forwarded-Proto، وCaddy يفعل ذلك افتراضياً.
ولكي نرى الفرق بنينا سير عمل Workflow صغيراً يرد بعنوان الاستئناف $execution.resumeUrl، وهو العنوان الذي يرسله n8n لمن يجب أن يوافق أو يرد في خطوة انتظار، مثل رابط موافقة يصل إلى مدير بالبريد. ومع الإعداد الصحيح كان الرد كما يلي:
curl -k --resolve n8n.localhost:8443:127.0.0.1 -X POST https://n8n.localhost:8443/webhook/urls{"resumeUrl":"https://n8n.localhost:8443/webhook-waiting/2?signature=31293533169354a1d75c40c9b1e703ddc5f70f1689c36ffe0fc6201c4e382a4b","forwardedFor":"172.22.0.1"}نكسره: نحذف العنوان العام
أعدنا تشغيل الرئيسي وحده دون N8N_WEBHOOK_URL ودون N8N_PROXY_HOPS، فأصبح يعلن عن عنوان المحرر بالمنفذ الداخلي:
WEBHOOK_URL= PROXY_HOPS=0 docker compose up -d lab-auto-n8nEditor is now accessible via:
https://n8n.localhost:5678ولكن الطلب نفسه بقي يرد بالعنوان الصحيح:
{"resumeUrl":"https://n8n.localhost:8443/webhook-waiting/523?signature=d0bc30e78a0793caf20cb15118c45f530865bdd430f81358e54214473493f432","forwardedFor":"172.22.0.1"}والسبب أن التشغيل لا يحدث في الرئيسي، وإنما في ال Worker، وال Workers ما زالت تعمل بالإعداد القديم. وهذه نقطة يقع فيها كثيرون: تغير متغيراً في الرئيسي فتظن أنه طبق، ثم تجد أن نصف السلوك يأتي من ال Workers. وعندما أعدنا تشغيل ال Workers بالإعداد الخاطئ نفسه أصبح العنوان خاطئاً:
{"resumeUrl":"https://n8n.localhost:5678/webhook-waiting/524?signature=102cbc8fd80414714caecb15a536d8aa5983606f00a7a95bc7bdb197aefb0a4e","forwardedFor":"172.22.0.1"}وهذا العنوان لا يصل إليه أحد من الخارج، فالمنفذ 5678 غير منشور أصلاً:
000 Failed to connect to n8n.localhost port 5678 after 2025 ms: Could not connect to serverأي أن رابط الموافقة الذي يصل إلى المدير لا يفتح، وسير العمل Workflow يبقى ينتظر إلى الأبد، ولا يظهر أي خطأ في n8n نفسه. والأمر نفسه يحدث مع العقد Nodes التي تسجل Webhook عند خدمة خارجية مثل GitHub Trigger، فتسجل عنواناً لا يصل إليه أحد. ثم أعدنا الإعداد الصحيح بالأمر docker compose up -d.
قياس الحمل على Worker اثنين
سير العمل Workflow في هذا الاختبار Webhook ثم عقدة Code بلغة JavaScript تحسب المجموع، أي أن كل طلب يمر على مشغلات الكود Task Runners الخارجية. وأرسلنا 500 طلب من عشرة عملاء متوازيين عبر Caddy، بعد عشرين طلباً للتسخين:
{"sent": 500, "concurrency": 10, "codes": {"200": 500}, "throughput_rps": 11.4, "resp_ms_p50": 868.4, "resp_ms_p95": 1305.8}والذاكرة والمعالج من docker stats قبل الحمل:
lab-auto-caddy 0.00% 17.47MiB / 31.29GiB
lab-auto-n8n 0.00% 294.9MiB / 31.29GiB
lab-auto-pg 0.00% 71.71MiB / 31.29GiB
lab-auto-redis 0.26% 13.45MiB / 31.29GiB
lab-auto-runners1 0.00% 10.93MiB / 31.29GiB
lab-auto-runners2 0.04% 5.25MiB / 31.29GiB
lab-auto-worker1 0.09% 241.7MiB / 31.29GiB
lab-auto-worker2 0.19% 247.4MiB / 31.29GiBوأثناء الحمل:
lab-auto-caddy 7.67% 22MiB / 31.29GiB
lab-auto-n8n 77.52% 368.1MiB / 31.29GiB
lab-auto-pg 57.32% 87.36MiB / 31.29GiB
lab-auto-redis 14.43% 17.01MiB / 31.29GiB
lab-auto-runners1 6.27% 155.9MiB / 31.29GiB
lab-auto-runners2 5.58% 153.5MiB / 31.29GiB
lab-auto-worker1 190.61% 303.6MiB / 31.29GiB
lab-auto-worker2 208.10% 314.6MiB / 31.29GiBثم عددنا في سجل كل Worker التشغيلات Executions التي بدأها، وسألنا قاعدة البيانات عن حالة التشغيلات Executions:
lab-auto-worker1 262 started, 262 finished
lab-auto-worker2 260 started, 260 finished
status | mode | count
---------+---------+-------
success | webhook | 522وفي النتائج أعلاه لاحظ التالي:
- العدد 522 هو 500 طلب الاختبار مع عشرين طلب التسخين وطلبين قبلهما، وكلها نجحت، وتوزعت بالتساوي تقريباً على ال Worker اثنين دون أي إعداد منا.
- الإعداد كله بثمانية Containers استهلك نحو 900 ميجابايت دون عمل، ونحو 1.4 جيجابايت تحت الحمل، وأغلبه في الرئيسي وال Workers.
- كل Worker استخدم نحو نواتين أثناء الحمل، والرئيسي نحو ثلاثة أرباع نواة، وقاعدة البيانات أكثر من نصف نواة، لأن كل تشغيل يكتب في PostgreSQL.
- في مقال الأدوات وصل n8n في Container واحد إلى 6.6 طلب في الثانية بسير عمل Workflow مختلف، وهنا 11.4، ولا نقارن الرقمين مباشرة لأن سير العمل Workflow مختلف والجهاز كان مشغولاً بأعمال أخرى، وإنما المهم أن العمل توزع وأن الرئيسي بقي متاحاً للمحرر.
وإذا أضفت Workers فتذكر أن كل واحد يفتح اتصالات بقاعدة البيانات، فراجع حد الاتصالات في PostgreSQL، وقد شرحنا ذلك في PostgreSQL للفرق.
النسخ الاحتياطي والاستعادة
بحسب توثيق النسخ الاحتياطي تتكون النسخة الكاملة من جزأين، والصورة التالية تبينهما وما يحدث عندما ينقص أحدهما:

ولاحظ أن أوامر التصدير n8n export:workflow --backup وn8n export:credentials --backup ليست نسخة احتياطية كاملة، فالتوثيق نفسه يذكر أنها لا تحتوي المستخدمين وأدوارهم، ولا سجل التشغيلات Executions، ولا المتغيرات، ولا مفتاح التشفير، وأنها تكفي لنقل سير العمل Workflow بين نسختين وليس لاستعادة نسخة كاملة. والنسخة الصحيحة هي pg_dump لقاعدة البيانات، ومعها المفتاح، كما يلي:
docker exec lab-auto-pg pg_dump -U n8n -d n8n -Fc -f /tmp/n8n.dump
docker cp lab-auto-pg:/tmp/n8n.dump backup/n8n.dumpثم استعدناها إلى قاعدة جديدة اسمها n8n_restore، ونظرنا إلى بيانات الاعتماد فيها:
docker exec lab-auto-pg psql -U n8n -d postgres -c "create database n8n_restore owner n8n;"
docker exec lab-auto-pg pg_restore -U n8n -d n8n_restore --no-owner /tmp/n8n.dump
docker exec lab-auto-pg psql -U n8n -d n8n_restore -c "select name, type, left(data, 24) || '...' as data_start from credentials_entity;" name | type | data_start
-------------------+----------------+-----------------------------
Invoice API token | httpHeaderAuth | U2FsdGVkX19qOY5tRka1lQzi...
(1 row)والحقل data مشفر بمفتاح التشفير، فمن يسرق نسخة قاعدة البيانات وحدها لا يقرأ بيانات الاعتماد، وهذا جيد، ولكنه يعني أيضاً أنك أنت لا تقرؤها إذا فقدت المفتاح.
نكسره: الاستعادة بمفتاح جديد
الآن سوف نفترض أن السيرفر احترق، وأن لديك نسخة قاعدة البيانات، ولكن ملف .env كان على السيرفر نفسه ولم يحفظ في مكان آخر، فشغلت n8n جديداً على القاعدة المستعادة بمفتاح جديد. وشغلنا بالمفتاح الجديد ثم بالمفتاح الأصلي أمر تصدير بيانات الاعتماد مفكوكة --decrypted، وهو الأمر الذي يحتاج المفتاح الصحيح:
docker run --rm --network lab-auto-n8n-net \
-e DB_TYPE=postgresdb -e DB_POSTGRESDB_HOST=lab-auto-pg -e DB_POSTGRESDB_DATABASE=n8n_restore \
-e DB_POSTGRESDB_USER=n8n -e DB_POSTGRESDB_PASSWORD="$PG_PASSWORD" \
-e N8N_ENCRYPTION_KEY="$KEY" n8nio/n8n:2.43.4 export:credentials --all --decryptedوالمخرج سوف يكون كما يلي، بعد أن حذفنا منه أسطر التحذيرات التي لا علاقة لها بالاختبار:
== key: wrong
Acquiring database migration lock...
Could not read the instance identity from the DB, using derived values
Error exporting credentials. See log messages for details.
Credentials could not be decrypted. The likely reason is that a different "encryptionKey" was used to encrypt the data.
Credentials could not be decrypted. The likely reason is that a different "encryptionKey" was used to encrypt the data.
== key: original
Acquiring database migration lock...
[{"updatedAt":"2026-10-14T12:14:51.671Z","createdAt":"2026-10-14T12:14:51.671Z","id":"labAutoCred00001","name":"Invoice API token","data":{"name":"Authorization","value":"Bearer lab-secret-123"},"type":"httpHeaderAuth","isManaged":false,"isGlobal":false,"isResolvable":false,"resolvableAllowFallback":false,"resolverId":null,"usageScope":"project","pendingAuthorizationExpiresAt":null}]وفي المخرج أعلاه لاحظ التالي:
- بالمفتاح الجديد بدأ n8n وقرأ قاعدة البيانات بشكل طبيعي، فسير العمل Workflow موجود، ولكن كل بيانات الاعتماد لا تفك. وفي نسخة حقيقية فيها عشرات بيانات الاعتماد لعشرات الأنظمة، هذا يعني أن تعيد إنشاءها كلها وأن تطلب مفاتيح جديدة من كل نظام.
- بالمفتاح الأصلي عادت القيمة كاملة كما أدخلناها.
- لذلك احفظ المفتاح في مخزن الأسرار مع نسخ قاعدة البيانات، وليس في القرص نفسه، واختبر الاستعادة على سيرفر آخر بالمفتاح المحفوظ، كما شرحنا في النسخ الاحتياطي بقاعدة 3-2-1.
export:credentials --decrypted يطبع كل بيانات الاعتماد نصاً واضحاً، والتوثيق يحذر من ذلك. استخدمناه هنا لإثبات أن المفتاح يعمل فقط، فلا تحفظ مخرجه في ملف، ولا تشغله على نسختك الحقيقية إلا عند الحاجة.الأمان
n8n يحمل مفاتيح كل الأنظمة التي يربطها، فهو هدف ثمين، وفي 2026 نشرت n8n عدداً كبيراً من التحذيرات الأمنية في صفحة التحذيرات في المستودع: في القائمة التي اطلعنا عليها يوم 14 أكتوبر 2026 كان هناك 26 تحذيراً منشوراً في أغسطس 2026 (16 منها بخطورة عالية)، و49 في سبتمبر 2026 (27 منها عالية). وأشهر الثغرات التي يجب أن تعرفها:
| الثغرة | تاريخ النشر | الخطورة | ما هي | الإصلاح |
|---|---|---|---|---|
| CVE-2025-68613 | 19 ديسمبر 2025 | 9.9 حرجة | تعبيرات يكتبها مستخدم مسجل في سير العمل Workflow تنفذ كوداً على السيرفر بصلاحيات n8n | 1.120.4 و1.121.1 و1.122.0 |
| CVE-2026-21858 | 8 يناير 2026 | 10.0 حرجة | مهاجم دون حساب يقرأ ملفات من السيرفر عبر سير عمل Workflow يستخدم النماذج Forms، وسمته الشركة التي اكتشفتها Ni8mare | 1.121.0 |
| GHSA-728h-pmr2-7cgh | 30 سبتمبر 2026 | عالية | تجاوز توقيع HMAC في خطوة الانتظار Send and Wait يسمح بالموافقة على تشغيل منتظر دون تسجيل دخول | 2.41.4 و2.42.1 |
والثغرة الأولى أضافتها وكالة CISA الأمريكية إلى قائمة الثغرات المستغلة فعلاً KEV في 11 مارس 2026، أي أن هناك من استغلها في هجمات حقيقية، وليست ثغرة نظرية. والدرس من هذه القائمة أن n8n ليس برنامجاً تثبته وتنساه، وإنما يحتاج تحديثاً منتظماً مثل نظام التشغيل نفسه.
وفيما يلي ما نطبقه على أي تثبيت:
- مشغلات الكود Task Runners الخارجية: التوثيق يذكر أنها خط العزل الوحيد بين الكود الذي يكتبه المستخدم وn8n نفسه، وأن بدونها أو في الوضع الداخلي Internal يستطيع أي شخص يعدل سير عمل Workflow أن يقرأ قاعدة البيانات ومفتاح التشفير وبيانات الاعتماد. لذلك استخدم الوضع الخارجي External كما في ملف Compose أعلاه.
- لا تنشر المحرر على الإنترنت إذا لم تحتج: انشر مسارات
/webhook/و/webhook-waiting/فقط، واجعل المحرر خلف VPN أو خلف authentik Forward Auth. - احم كل Webhook: عقدة Webhook فيها حقل Authentication، أو تحقق من التوقيع في الخطوة التالية مباشرة.
- شغل الفحص الأمني المدمج: الأمر
n8n auditيفحص النسخة ويطبع تقريراً، وسوف نراه أدناه. - أغلق ما لا تستخدمه: مثل ال API العامة بالمتغير
N8N_PUBLIC_API_DISABLED=true، والحزم المجتمعية Community Packages إذا لم تكن تحتاجها، لأن كل حزمة كود من طرف ثالث يعمل داخل n8n. - التحقق بخطوتين 2FA: يستطيع كل مستخدم تفعيله من إعداداته الشخصية في النسخة المجانية، فاطلبه من الجميع، أما فرضه على كل المستخدمين من سياسات الأمان فمتاح في Business وEnterprise.
وشغلنا الفحص الأمني على نسختنا:
docker exec lab-auto-n8n n8n auditوالمخرج طويل بصيغة JSON، وفيه ثلاثة أقسام للمخاطر هي credentials وnodes وinstance، ونعرض هنا جزءاً من قسم instance كما طبعه:
{
"Instance Risk Report": {
"risk": "instance",
"sections": [
{
"title": "Unprotected webhooks in instance",
"description": "This webhook node has the \"Authentication\" field set to \"None\" and is not directly connected to a node to validate the payload. Every unprotected webhook allows your workflow to be called by any third party who knows the webhook URL.",
"recommendation": "Consider setting the \"Authentication\" field to an option other than \"None\", or validating the payload with one of the following nodes: n8n-nodes-base.if,n8n-nodes-base.switch,n8n-nodes-base.code,n8n-nodes-base.function,n8n-nodes-base.functionItem.",
"location": [
{
"kind": "node",
"workflowId": "labAutoCUrls0001",
"workflowName": "Show my public URLs",
"nodeId": "e1000000-0000-4000-8000-000000000003",
"nodeName": "Webhook",
"nodeType": "n8n-nodes-base.webhook"
}
]
},
{
"title": "Outdated instance",
"description": "This n8n instance is outdated. Currently at version 2.43.4, missing 1 update.",
"recommendation": "Consider updating this n8n instance to the latest version to prevent security vulnerabilities.",
"nextVersions": [
{
"name": "2.43.5",
"createdAt": "2026-10-14T10:42:25.990Z",
"hasSecurityIssue": null,
"hasSecurityFix": null,
"securityIssueFixVersion": null,
"hasBreakingChange": false,
"documentationUrl": "https://docs.n8n.io/release-notes/#n8n2435?utm_source=n8n_app&utm_medium=instance_upgrade_releases",
"nodes": [],
"description": "Includes <strong>bug fixes</strong>"
}
]
},
{
"title": "Security settings",
"description": "This n8n instance has the following security settings.",
"recommendation": "Consider adjusting the security settings for your n8n instance based on your needs. See: https://docs.n8n.io/hosting/configuration/environment-variables/",
"settings": {
"features": {
"communityPackagesEnabled": true,
"versionNotificationsEnabled": true,
"templatesEnabled": true,
"publicApiEnabled": true
},
"nodes": {
"nodesExclude": "n8n-nodes-base.executeCommand, n8n-nodes-base.localFileTrigger, n8n-nodes-base.e2eTest, n8n-nodes-base.dynamicCredentialCheck",
"nodesInclude": "none"
},
"telemetry": {
"diagnosticsEnabled": false
}
}
}
]
}
}وفي المخرج أعلاه لاحظ التالي:
- الفحص اكتشف أن ال Webhook في سير العمل Workflow
Show my public URLsدون حماية، ولم يذكر سير عمل Workflow الطلبات، والسبب أنه متصل مباشرة بعقدة Code، والفحص يعتبرها مكاناً للتحقق من البيانات. - الفحص اكتشف أن إصداراً أحدث هو 2.43.5 صدر في اليوم نفسه الذي شغلنا فيه المختبر، أي أن النسخة تقادمت خلال ساعات، وهذا يؤكد ما قلناه عن التحديث المنتظم.
- قسم الإعدادات يبين أن الحزم المجتمعية وال API العامة مفعلة افتراضياً، فأغلقها إن لم تكن تحتاجها.
الترقيات
تصدر n8n إصدارات بشكل متكرر جداً، وفي الأسبوع الذي كتبنا فيه هذا المقال صدر 2.42.4 و2.42.5 و2.42.6 و2.42.7 و2.43.0 إلى 2.43.5 و2.44.0 التجريبي، كما في صفحة الإصدارات. والفرع 1.x ما زال يستلم إصلاحات أمنية (1.123.84 في 8 أكتوبر 2026)، فإذا كنت عليه فلست مجبراً على القفز اليوم، ولكن خطط للانتقال. وطريقة الترقية التي نتبعها:
- اقرأ ملاحظات الإصدار، وانتبه إلى قسم Breaking Changes، فالانتقال من 1.x إلى 2.0 مثلاً غير تفعيل سير العمل Workflow من Active إلى Publish، وفي الإصدار 2.35.0 أصبح المتغير
WEBHOOK_URLمهملاً لصالحN8N_WEBHOOK_URL. - خذ نسخة
pg_dumpقبل الترقية، فالإصدار الجديد قد يعدل جداول قاعدة البيانات Migrations عند أول تشغيل، ولا يوجد رجوع تلقائي. - غير الإصدار في الملف لكل من
n8nio/n8nوn8nio/runnersمعاً، لأنهما يجب أن يتطابقا. - جرب الترقية على نسخة اختبار من قاعدة البيانات أولاً إذا كانت لديك سير عمل Workflow حرجة.
- شغل
docker compose pullثمdocker compose up -d، وراقب سجل الرئيسي حتى يظهرEditor is now accessible، ثم جرب سير عمل Workflow حرجاً.
ولم نشغل ترقية فعلية في هذا المختبر، والخطوات أعلاه من التوثيق ومن طريقة عملنا مع الأدوات الأخرى.
المستخدمون والدخول الموحد
في النسخة المجانية Community يوجد مالك واحد ومستخدمون يدعوهم، ويرى كل مستخدم سير العمل Workflow وبيانات الاعتماد التي أنشأها فقط، ولا توجد مشاركة بينهم، ولا مشاريع Projects. أما الدخول الموحد SSO عبر SAML أو OIDC أو LDAP فمتاح في خطتي Business وEnterprise للنسخة التي تستضيفها بنفسك. فإذا كانت مؤسستك تستخدم authentik كما شرحنا في تثبيت authentik، فإن ربط n8n به عبر OIDC يحتاج ترخيصاً مدفوعاً، والبديل في النسخة المجانية أن تضع المحرر خلف Forward Auth، مع بقاء حسابات n8n نفسها منفصلة.
أخطاء شائعة
- ترك n8n يولد مفتاح التشفير ثم نسيانه: يعمل كل شيء حتى أول استعادة.
- تغيير متغير في الرئيسي فقط: رأينا أن ال Workers هي التي تنفذ، فالإعداد المشترك يجب أن يصل إليها كلها.
- نسيان
N8N_WEBHOOK_URLخلف ال Reverse Proxy: روابط الموافقة وال Webhooks المسجلة عند الخدمات الخارجية تشير إلى منفذ لا يصل إليه أحد. - إصدار runners مختلف عن إصدار n8n: التوثيق يشترط تطابقهما.
- اعتبار
export --backupنسخة احتياطية: لا يحتوي المستخدمين ولا التشغيلات Executions ولا المفتاح. - نشر المحرر على الإنترنت دون حماية إضافية: مع عدد التحذيرات الأمنية في 2026، كل طبقة تقلل ما يصل إليه المهاجم.
تدريب عملي
- أضف Worker ثالثاً إلى ملف Compose مع Container runners له، وأعد قياس الحمل، ولاحظ هل يرتفع عدد الطلبات في الثانية أم يصبح PostgreSQL هو الحد.
- أوقف Redis أثناء الحمل لعشر ثوان ثم شغله، ولاحظ ماذا يحدث للطلبات التي وصلت أثناء التوقف.
- خذ نسخة
pg_dumpوانقلها مع المفتاح إلى جهاز آخر، واستعدها هناك، ثم تأكد أن سير عمل Workflow يستخدم بيانات اعتماد يعمل.
حذف المختبر
docker compose down -vالخلاصة
وصلنا لنهاية الموضوع، وأهم ما فيه:
- في الإنتاج استخدم PostgreSQL ومفتاح تشفير تحدده أنت ومشغلات كود خارجية، ثم أضف وضع الطابور Queue Mode وال Workers عندما تحتاج.
- الإعداد يجب أن يكون نفسه في الرئيسي وفي كل Worker، وأسهل طريقة لذلك بيئة مشتركة واحدة في ملف Compose.
- خلف ال Reverse Proxy حدد
N8N_WEBHOOK_URLوN8N_PROXY_HOPS، وإلا ظهرت روابط لا يصل إليها أحد دون أي خطأ. - النسخة الاحتياطية هي قاعدة البيانات مع مفتاح التشفير، وقاعدة البيانات وحدها تفقدك كل بيانات الاعتماد.
- حدث n8n بانتظام، وشغل
n8n audit، ولا تنشر المحرر على الإنترنت دون طبقة حماية. - SSO والمشاركة بين المستخدمين في الخطط المدفوعة.
وفي المقال القادم بإذن الله سوف نبني سير عمل Workflow حقيقياً على هذا التثبيت: من نموذج أو بريد إلى تذكرة في GLPI، ثم موافقة وتسليم جهاز في Snipe-IT، مع سير عمل Workflow أخطاء واختبار وحفظ في Git.
سجل التحديثات
- أكتوبر 2026: كتابة المقال، وتشغيل المختبر على n8n 2.43.4 مع runners 2.43.4 وPostgreSQL 17.11 وRedis 8.10.2 وCaddy 2.11.7، والاطلاع على التوثيق والتحذيرات الأمنية بتاريخ 14 أكتوبر 2026.