لماذا تستضيف Trigger.dev ذاتيًا على خادم VPS
يستبدل Trigger.dev الطوابير المصنوعة يدويًا (BullMQ، وcron هشّة، وLambda التي تنتهي مهلتها) بمنصة موحّدة: مهام دائمة، وإعادات محاولة تلقائية، وإدارة للتزامن، ولوحة تحكم في الزمن الحقيقي. تفرض النسخة السحابية رسومًا حسب عدد عمليات التنفيذ وتحدّ من مدة المهام، وهو ما يصبح مُقيِّدًا سريعًا لمعالجة ETL أو إرسال رسائل بريد إلكتروني بالجملة أو استدعاءات API بطيئة.
وبالاستضافة الذاتية على خادم VPS، تُبقي workers لديك عندك: لا تمرّ مفاتيح API الطرف الثالث (OpenAI، وStripe، وResend) عبر أي طرف ثالث، ويمكن أن تعمل مهامك 10 دقائق أو عدة ساعات دون أن تُقطع. تعتمد الحزمة على PostgreSQL وRedis وDocker، ما يجعلها قابلة لإعادة الإنتاج وسهلة النسخ الاحتياطي. التثبيت مجاني تمامًا: لا ترخيص، لا اشتراك — تدفع فقط تكلفة خادم VPS.
ما الذي تكسبه بالاستضافة الذاتية
- لا حدّ على مدة أو عدد عمليات تنفيذ مهامك في الخلفية.
- تبقى أسرارك (مفاتيح API، رموز) في بنيتك التحتية، وليس على خدمة SaaS طرف ثالث أبدًا.
- تكلفة ثابتة قابلة للتوقّع: خادم VPS واحد بدلًا من فاتورة ترتفع مع الحجم.
- لا مرور عبر الشبكة العمومية إن كانت workers لديك تعمل بجوار قاعدة بياناتك وتطبيقك.
- تحكّم كامل في الإصدارات ومتغيرات البيئة ومدة الاحتفاظ بالسجلات.
- إمكانية إطلاق المهام من webhooks الداخلية لديك دون كشف أي خدمة خارجية.
- تحديث في الوقت الذي تختاره: أنت تقرر متى تنتقل إلى إصدار جديد من Trigger.dev.
Trigger.dev ذاتي الاستضافة مقابل السحابة: ما الذي يتغير فعلًا
| المعيار | السحابة (SaaS) | VPS ذاتي الاستضافة |
|---|---|---|
| المدة القصوى لمهمة | محدودة (دقائق) | غير محدودة |
| التكلفة بالحجم | ترتفع مع عمليات التنفيذ | ثابتة (خادم VPS شهريًا) |
| الأسرار / مفاتيح API | تمر عبر السحابة | تبقى في بنيتك التحتية |
| التحديثات | تلقائية، مفروضة | في الوقت الذي تختاره |
| الوصول للشبكة الداخلية | مستحيل بدون نفق | مباشر دون كمون عمومي |
| الاحتفاظ بالسجلات | محدود بالخطة | تتحكم فيه بنفسك |
| الإعداد المبدئي | صفر إعداد | ~30 دقيقة (هذا الدليل) |
المتطلبات العتادية والبرمجية
Trigger.dev حزمة كثيفة الاستهلاك نسبيًا لأنها تجمع بين تطبيق الويب وworkers وPostgreSQL وRedis. خصّص خادم VPS بـ 4 غيغابايت RAM على الأقل و2 vCPU كحدّ أدنى لاستخدام إنتاجي خفيف؛ واستهدف 8 غيغابايت RAM و4 vCPU إن كنت تشغّل عددًا كبيرًا من المهام المتزامنة أو عمليات معالجة ثقيلة. احسب 40 غيغابايت من قرص SSD لقاعدة البيانات والسجلات وصور Docker.
على الصعيد البرمجي: Docker Engine 24+ وإضافة Docker Compose v2 (تحقّق بـ docker compose version)، واسم نطاق يشير إلى عنوان IP الخاص بالخادم (مثل trigger.mydomain.com)، والمنفذ 443 مفتوحًا لـ HTTPS. سرّان لا غنى عنهما: MAGIC_LINK_SECRET (المصادقة بدون كلمة مرور) وENCRYPTION_KEY (32 محرفًا سِتّ عشريًا، يُشفّر متغيرات البيئة للمشاريع). ولّدهما قبل أن تبدأ — لا يمكن إعادة توليدهما دون كسر البيانات الموجودة.
تثبيت Trigger.dev باستخدام Docker في 6 خطوات
تحضير الخادم VPS وتثبيت Docker
اتصل عبر SSH بمستخدم sudo، وحدّث النظام (apt update && apt upgrade -y) ثم ثبّت Docker بأمر واحد: curl -fsSL https://get.docker.com | sh. أضف مستخدمك إلى مجموعة docker (usermod -aG docker $USER) لتجنّب استخدام sudo دائمًا. أنشئ مجلدًا مخصّصًا: mkdir -p /opt/trigger && cd /opt/trigger. تحقّق من توفّر Compose v2 بـ docker compose version — يجب أن تُظهر النتيجة v2.x.x كحدّ أدنى.
الحصول على حزمة الاستضافة الذاتية الرسمية
استنسخ المستودع الرسمي: git clone https://github.com/triggerdotdev/trigger.dev /opt/trigger/src. انتقل إلى المجلد الفرعي للنشر: cd /opt/trigger/src/docker. يحتوي هذا المجلد على docker-compose.yml الذي ينسّق تطبيق الويب (webapp) وworkers وPostgreSQL وRedis. انسخ ملف المثال إلى إعداداتك: cp .env.example .env. لا تشغّل أي شيء قبل إعداد .env — ستُرفض الحزمة بالبدء بالقيم الافتراضية.
توليد الأسرار وضبط النطاق
افتح .env في محرّرك واضبط هذه المتغيرات كحدّ أدنى:
- ENCRYPTION_KEY: openssl rand -hex 16 (16 بايت = 32 حرف سِتّ عشري)
- MAGIC_LINK_SECRET: openssl rand -hex 16 (بالمثل)
- LOGIN_ORIGIN: https://trigger.mydomain.com
- APP_ORIGIN: https://trigger.mydomain.com
- POSTGRES_PASSWORD: كلمة مرور قوية (openssl rand -base64 24)
- REDIS_PASSWORD: بالمثل
aترك DATABASE_URL وREDIS_URL كما هما إن كنت تستخدم خدمات Compose الداخلية — فهي تُحيل إلى أسماء خدمات Docker. اضبط أيضًا SESSION_SECRET بـ openssl rand -hex 32.
تشغيل الحزمة وإنشاء أول حساب
شغّل المجموعة كلها في الخلفية: docker compose up -d. تابع عمليات ترحيل قاعدة البيانات في الزمن الحقيقي: docker compose logs -f webapp. انتظر رسالة Listening on port 3030 قبل المتابعة — قد تستغرق عمليات الترحيل 30 إلى 60 ثانية في التشغيل الأول. بمجرد انطلاق التطبيق، يظهر magic link التسجيل في السجلات: انسخه وافتحه في متصفّحك لإنشاء أول حساب مسؤول. إن فاتك الرابط: docker compose logs webapp | grep magic.
الكشف عبر وكيل عكسي بـ HTTPS
ضع Caddy أمام التطبيق لإدارة TLS تلقائيًا. أنشئ /etc/caddy/Caddyfile بهذا المحتوى الأدنى:
trigger.mydomain.com {
reverse_proxy localhost:3030
}أعد تشغيل Caddy (systemctl reload caddy): تُصدر Let's Encrypt الشهادة في ثوانٍ. مع nginx، أنشئ vhost يُوكّل إلى http://127.0.0.1:3030 وفعّل شهادة عبر certbot --nginx. تحقّق بعد ذلك من أن https://trigger.mydomain.com يستجيب بشكل صحيح قبل المتابعة.
ربط أول مشروع TypeScript
في مشروع Node.js الخاص بك، ثبّت الـ SDK: npm install @trigger.dev/sdk. صادق الـ CLI على نسختك: npx trigger.dev@latest login --api-url https://trigger.mydomain.com. ثم أنشئ أول مشروع في لوحة التحكم، واسترجع مفتاح المشروع السري (sk_...) وأضفه في ملف .env المحلي: TRIGGER_SECRET_KEY=sk_.... هيّئ الإعدادات بـ npx trigger.dev@latest init وانشر أول مهمة بـ npx trigger.dev@latest deploy.
معالجة الأخطاء: المشكلات الشائعة وحلولها
فيما يلي أكثر خمسة أخطاء شيوعًا عند تثبيت Trigger.dev بالاستضافة الذاتية.
Error: ENCRYPTION_KEY must be 32 characters — استخدمت openssl rand -base64 16 بدلًا من openssl rand -hex 16. تُنتج صيغة base64 محارف خارج نطاق السِّتّ عشري. أعد التوليد بـ -hex 16 (32 حرفًا بالضبط).
webapp exited with code 1 عند التشغيل — تحقّق من السجلات الكاملة بـ docker compose logs webapp. السبب الأكثر شيوعًا: DATABASE_URL خاطئة أو PostgreSQL لم يكتمل تشغيله بعد. انتظر 10 ثوانٍ وأعد التشغيل بـ docker compose restart webapp.
لا يظهر magic link لإنشاء الحساب — ربما انطلق التطبيق قبل انتهاء عمليات الترحيل. شغّل docker compose restart webapp وراقب السجلات من البداية. إن ظلّ الرابط غائبًا، تحقّق من أن LOGIN_ORIGIN يطابق نطاقك تمامًا (بدون شرطة مائلة في النهاية).
Failed to connect في الـ CLI عند login — الوكيل العكسي ليس نشطًا بعد أو DNS لم ينتشر إلى خادمك. اختبر محليًا بـ curl http://127.0.0.1:3030/healthcheck من الخادم: إن استجاب، المشكلة في جهة الوكيل أو DNS.
المهمة تُنشر لكنها لا تُنفَّذ — تحقّق من أن workers تعمل: docker compose ps يجب أن يُظهر خدمة worker بحالة running. إن توقّف الـ worker، أعد تشغيله بـ docker compose up -d worker. تحقّق أيضًا من أن TRIGGER_SECRET_KEY في مشروعك يطابق مفتاح المشروع الصحيح في لوحة التحكم.
تأمين النسخة وصيانتها
تعرض نسخة Trigger.dev لوحة التحكم وAPI على النطاق ذاته. بعض الاحتياطات تُقلّص سطح الهجوم دون تعقيد العمليات.
جدار الحماية: احجب جميع المنافذ باستثناء 22 (SSH) و80 و443. يجب ألا يكون المنفذ 3030 متاحًا مباشرةً من الخارج — فهو مُخصَّص للوكيل العكسي المحلي.
تدوير الأسرار: يمكن تدوير MAGIC_LINK_SECRET دون كسر البيانات. أما ENCRYPTION_KEY فيُشفّر متغيرات البيئة للمشاريع — تدويره يستلزم ترحيل بيانات. احفظهما في مدير أسرار (Bitwarden أو 1Password أو HashiCorp Vault).
التحديثات: يُصدر Trigger.dev إصداراته على GitHub. للتحديث: اسحب الإصدار الجديد (git pull في /opt/trigger/src)، وأعد بناء الصور (docker compose pull)، وأعد التشغيل (docker compose up -d). تُطبَّق عمليات ترحيل قاعدة البيانات تلقائيًا عند بدء webapp.
النسخ الاحتياطية: جدوِل تفريغًا يوميًا لـ PostgreSQL نحو تخزين خارجي. cron بسيط: 0 3 * * * docker exec trigger-postgres-1 pg_dump -U postgres trigger | gzip > /opt/backups/trigger-$(date +%F).sql.gz.
التوسّع الأفقي للعمال
اعزل workers عن تطبيق الويب في حاويات منفصلة، وحُدّ من تزامنها عبر المتغير WORKER_CONCURRENCY (الافتراضي: 10). وبالنسبة للمهام الشديدة الاستهلاك للمعالج، أضف خادم VPS ثانيًا مخصّصًا للـ workers يشير إلى نفس PostgreSQL وRedis: بذلك تتوسّع أفقيًا دون المساس بلوحة التحكم. الـ workers عديمة الحالة — تحتاج فقط إلى DATABASE_URL وREDIS_URL وENCRYPTION_KEY للانضمام إلى الأسطول. على VPS صغير، ابدأ بـ WORKER_CONCURRENCY=3 لتجنّب إشباع الذاكرة خلال ذروة المهام.
كتابة ونشر أول مهمة Trigger.dev
مهمة Trigger.dev هي دالة TypeScript مُصدَّرة من ملف trigger/ في مشروعك. إليك مثالًا أدنى لإرسال بريد إلكتروني مؤجَّل:
import { task } from "@trigger.dev/sdk/v3";
export const sendWelcomeEmail = task({
id: "send-welcome-email",
run: async (payload: { userId: string; email: string }) => {
// منطق الإرسال هنا
await sendEmail(payload.email, "مرحبًا!");
return { sent: true };
},
});انشر بـ npx trigger.dev@latest deploy. تُظهر لوحة التحكم مهمتك تحت تبويب Tasks. أطلق تشغيلًا تجريبيًا من لوحة التحكم أو من كودك: await sendWelcomeEmail.trigger({ userId: "u1", email: "[email protected]" }). تُطبَّق إعادات المحاولة التلقائية عند الخطأ — قابلة للتهيئة بالخيار retry في task().
للمهام الطويلة (استيراد CSV، معالجة صور)، استخدم wait.for() لتعليق التنفيذ وعدم حجب worker خلال فترات الانتظار الشبكية: يستأنف Trigger.dev المهمة من حيث توقّفت، حتى بعد إعادة تشغيل الحاوية.
حالات الاستخدام الأكثر ملاءمة للاستضافة الذاتية
- معالجة ETL: استيراد وتحويل وتحميل أحجام كبيرة من البيانات دون انتهاء مهلة.
- الإرسال المعاملاتي الضخم: حملات بريد إلكتروني أو إشعارات مع تحكّم في التدفّق.
- مسارات الذكاء الاصطناعي: استدعاءات متسلسلة لـ OpenAI وAnthropic وHugging Face مع إدارة إعادات المحاولة عند تجاوز الحصة.
- مزامنة تكاملات الطرف الثالث: Stripe webhooks وShopify وHubSpot — دون الاعتماد على SaaS وسيط.
- المهام المجدولة الحرجة: استبدال cron هشّة بمهام تمتلك سجل تنفيذ وتنبيهات.
- توليد تقارير PDF أو تصديرات ثقيلة: مهام تستغرق دقائق عدة دون حدّ للمدة.
Trigger.dev مجاني تمامًا عند الاستضافة الذاتية: لا يُشترط أي ترخيص تجاري للاستخدام الخاص أو المهني على بنيتك التحتية الخاصة. تُغطّي رخصة MIT الكود مفتوح المصدر. الكود المملوك فقط لنسخة Enterprise (SAML SSO، سجلات التدقيق المتقدمة) مستثنى — وللغالبية العظمى من الفرق، تكفي النسخة المجتمعية ذاتية الاستضافة تمامًا.