انتقل إلى المقال
Aniq-UI

Northstackانشر Northstack

انشر Northstack

ضع الموقع ولوحة التحكم وواجهة API على الإنترنت: Docker Compose على خادم واحد، أو تطبيق واحد لكل مضيف من Dockerfile الخاص به، أو Node.js مباشرة، مع البدء فارغًا ومسؤول منصة خاص بك، وتحديث الجداول بعد كل تحديث.

لحزمة الحزمة الكاملة

ثلاث طرق للنشر

الطريقةمناسبة لـما تحتاجه
Docker Compose على خادم واحدخادم VPS تتحكم فيه، والتطبيقات الثلاثة معًاالحزمة الكاملة، وDocker على الخادم، وخادم وكيل عكسي لـ HTTPS
تطبيق واحد لكل مضيف، من Dockerfile الخاص بهRailway وRender وFly.io ومضيفات أخرى تبني من Dockerfileمجلد كل تطبيق؛ ووحدة تخزين أو MySQL، واختياريًا حاوية تخزين (bucket)، لواجهة API
Node.js عاديأي مضيف NodeNode.js 22.13 أو إصدار أحدث من 22، أو 24.11 أو أحدث، وYarn 4 على المضيف

مهما كانت الطريقة التي تختارها، يدمج الموقع ولوحة التحكم عنوان واجهة API في JavaScript عند بنائهما، لذلك ابنهما بالعناوين العامة وليس المحلية أبدًا.

Docker Compose على خادم واحد

انسخ مجلد الحزمة إلى الخادم وضع ملف .env بجانب docker-compose.yml يحمل العناوين العامة الثلاثة. منها تُبنى المصادر المسموح بها في واجهة API، والروابط التي تكتبها في الدعوات وإعادة تعيين بيانات الدخول وعودة الدفع، وروابط تنزيل الفواتير، وعنوان الوسائط، وعنوان واجهة API في الواجهتين الأماميتين.

.env بجانب docker-compose.yml
SITE_URL=https://www.your-domain.com
ADMIN_URL=https://app.your-domain.com
API_URL=https://api.your-domain.com

ثم ابنِ وشغّل في الخلفية:

الطرفية
docker compose up --build -d
  • وجّه كل نطاق إلى الخادم عبر خادم وكيل عكسي يقدّم HTTPS (Caddy أو Nginx أو Traefik)، ويحوّل إلى المنافذ 3030 و3031 و8000.
  • انسخ back-end/.env.example إلى back-end/.env لمفاتيح الدفع والبريد والتخزين والذكاء الاصطناعي وMCP: تقرؤه حاوية واجهة API إذا وُجد، ويحتفظ docker-compose.yml بالقيم التي يجب أن تختلف داخل الحاوية. خلف الوكيل اضبط TRUST_PROXY=1 هناك، ليحسب حد تسجيل الدخول كل زائر على حدة بدلًا من الوكيل.
  • من دون JWT_SECRET خاص بك، تولّد واجهة API واحدًا عند أول تشغيل وتحفظه في وحدة التخزين northstack-data. وقاعدة البيانات والملفات المرفوعة في وحدة التخزين هذه أيضًا، فخذ منها نسخة احتياطية.
  • لتثبيت حقيقي، ابدأ وحدة التخزين الجديدة فارغة: ضع SEED_SAMPLE_DATA=false في ملف .env بجانب docker-compose.yml (وليس back-end/.env: يمرّر Compose هذه القيم الثلاث من هناك)، مع ADMIN_EMAIL وADMIN_PASSWORD لأول مسؤول منصة لديك، قبل أول docker compose up. أما ملف .env بجانب docker-compose.yml فلا يصل إلى واجهة API لهذا الغرض. راجع «البدء فارغًا» أدناه.
  • إذا تُركت على قيمتها الافتراضية (SEED_SAMPLE_DATA=true)، فإن أول تشغيل على وحدة تخزين جديدة يملأ مساحات العمل التجريبية وحساباتها، وكلها بكلمة المرور المنشورة. اجعلها ملكك قبل أن يصبح المشروع متاحًا، كما في «البدء من البيانات التجريبية» أدناه.

واجهة API من Dockerfile

وجّه المضيف إلى مجلد واجهة API (back-end/ في الحزمة الكاملة). تعمل الصورة بـ NODE_ENV=production، وتستمع على PORT (القيمة 8000 ما لم يضبط المضيف غيرها)، وتجيب GET /api/health حين تحمل قاعدة بياناتها المخطط، وتحفظ SQLite والملفات المرفوعة في /data.

  • اربط وحدة تخزين دائمة على /data. من دونها يبدأ كل نشر على قاعدة بيانات جديدة.
  • اضبط SEED_SAMPLE_DATA=false مع ADMIN_EMAIL وADMIN_PASSWORD، لتبدأ وحدة التخزين الجديدة بمسؤول منصة خاص بك ومن دون بيانات تجريبية. وإذا تُركت على true، وهي القيمة الافتراضية، فإن وحدة التخزين الجديدة تُملأ بالحسابات التجريبية وكلمة المرور المنشورة لها.
  • اضبط CORS_ORIGIN على عنواني الموقع ولوحة التحكم (مفصولين بفاصلة)، وFRONTEND_URL وDASHBOARD_URL على عنوان لوحة التحكم، وWEBSITE_URL على عنوان الموقع، وPUBLIC_API_URL على العنوان العام لواجهة API، وPUBLIC_MEDIA_URL على ذلك العنوان متبوعًا بـ /media.
  • على SQLite، تُنشأ وحدة التخزين التي لا قاعدة بيانات فيها مرة واحدة، كما يقول SEED_SAMPLE_DATA؛ أما القاعدة الموجودة فلا تُملأ مرة أخرى أبدًا ولا تتغير جداولها عند التشغيل (راجع «التحديث» أدناه).
  • اضبط JWT_SECRET خاصًا بك، أو دع الحاوية تولّد واحدًا وتحفظه في /data/.jwt-secret.
  • اضبط TRUST_PROXY=1: فمنصة الاستضافة تضع وكيلًا أمام الحاوية.
  • على MySQL (DB_TYPE=mysql ومتغيرات DB_* الخمسة)، لا تنشئ الحاوية الجداول. شغّل node dist/database/create-admin.js مرة واحدة بالبيئة نفسها (أو node dist/database/seeder.js لتثبيت تجريبي).
  • تبقى الملفات المرفوعة على وحدة التخزين بعد إعادة النشر؛ ولإبعادها عن الخادم اضبط متغيرات R2_* الخمسة لحاوية تخزين.

الموقع ولوحة التحكم من Dockerfile الخاص بكل منهما

وجّه المضيف إلى مجلد التطبيق وأعطه قيم NEXT_PUBLIC_* على أنها معاملات بناء، وليس متغيرات تشغيل: فهي تُدمج عند البناء. تقدّم كل صورة خادم Next.js المستقل على PORT (3030 للموقع و3031 للوحة التحكم، ما لم يحدد المضيف غيرهما).

معامل البناءالتطبيقالقيمة
NEXT_PUBLIC_API_BASE_URLكلاهماالعنوان العام لواجهة API متبوعًا بـ /api. إذا تُرك على قيمته الافتراضية http://localhost:8000/api، فإن التطبيق المنشور يستدعي جهاز الزائر نفسه.
NEXT_PUBLIC_SITE_URLالموقعالعنوان العام للموقع: الروابط الأساسية، وبدائل اللغات، وخريطة الموقع، وبطاقات المشاركة
NEXT_PUBLIC_DASHBOARD_URLالموقعالعنوان العام للوحة التحكم، الذي تفتحه «جرّب العرض الحي» و«استكشف العرض الحي» و«اطّلع على إدارة الأدوار» وزر تسجيل الدخول في /error/401 وعناوين /auth/* في الموقع
NEXT_PUBLIC_BASE_URLلوحة التحكمالعنوان العام للوحة التحكم: robots.txt وخريطة الموقع والبيانات الوصفية
NEXT_PUBLIC_WEBSITE_URLلوحة التحكمالعنوان العام للموقع، لروابط التوثيق والخصوصية والشروط
NEXT_PUBLIC_WEBSOCKET_BASE_URLلوحة التحكماختياري. العنوان العام لواجهة API من دون /api، لتحديثات الصلاحيات المباشرة؛ وإذا ترك فارغًا استخدمت لوحة التحكم NEXT_PUBLIC_API_BASE_URL من دون /api

يقرأ خادم الموقع واجهة API أيضًا حين يعرض الدفع وإيصاله. وإذا كان عنوان واجهة API العام يعمل من الخادم أيضًا فلا حاجة إلى شيء آخر؛ ويتجاوزه API_INTERNAL_URL وقت التشغيل حين يجب أن يستخدم الخادم عنوانًا آخر.

Node.js عادي

ابنِ كل تطبيق مرة واحدة على المضيف، ثم شغّله. اضبط .env الخاص بالواجهتين الأماميتين على العناوين العامة قبل yarn build.

التطبيقالبناءالتشغيل
APIyarn build، ثم مرة واحدة على قاعدة بيانات جديدة yarn admin:create:prodyarn start:prod
لوحة تحكم مساحة العملyarn buildyarn start (المنفذ 3031، أو PORT في .env الخاص بها)
الموقع العامyarn buildyarn start (المنفذ 3030)

ترتبط واجهة API بالعنوان 0.0.0.0 وتقرأ PORT. أبقِ ملف SQLite وMEDIA_UPLOAD_DIR على تخزين يبقى بعد النشر، أو استخدم MySQL وحاوية تخزين. في الإنتاج لا تنشئ واجهة API الجداول ولا تغيّرها بنفسها: ينشئها yarn admin:create:prod مع أول مسؤول منصة لديك، ويحدّثها yarn schema:prod بعد التحديث.

البدء فارغًا، مع مسؤول منصة خاص بك

يبدأ التثبيت الحقيقي من دون بيانات تجريبية ومع حساب واحد لك. في مجلد واجهة API، بعد yarn build:

الطرفية
yarn admin:create:prod
  • ينشئ الجداول وأدوار المنصة وإعداداتها، وأول مسؤول منصة من ADMIN_EMAIL وADMIN_PASSWORD (من 8 إلى 128 حرفًا) في البيئة أو back-end/.env. ويسألك في الطرفية عن أيٍّ منهما كان فارغًا، وADMIN_NAME اختياري.
  • لا ينشئ مساحة عمل ولا حسابًا تجريبيًا، ويرفض إذا كان هناك مسؤول منصة بالفعل. سجّل الدخول بهذا الحساب وأنشئ مساحة عملك في الإعداد الأولي.
  • يفعل yarn admin:create الشيء نفسه من المصدر، من دون بناء.
  • مع Docker، يفعل SEED_SAMPLE_DATA=false هذا عند أول تشغيل: إذا ضُبط ADMIN_EMAIL وADMIN_PASSWORD أنشأ المسؤول، وإلا أنشأ الجداول فقط وذكر سجله الأمر التالي الذي تشغّله، docker compose exec -u node api node dist/database/create-admin.js (ومع docker run، docker exec -it -u node <container> node dist/database/create-admin.js).

لا تملأ خادمًا عامًا بالبيانات التجريبية أبدًا

yarn seed:prod وyarn seed لتثبيت تجريبي فقط: يحمّلان الحسابات التجريبية بكلمة المرور المنشورة في هذا الدليل. يستطيع أي شخص يقرؤه تسجيل الدخول بصفته مسؤول المنصة لديك.

التحديث: الجداول بعد التحديث

لا توجد ترحيلات، وفي الإنتاج لا تغيّر واجهة API الجداول بنفسها. بعد تحديث يغيّر كوده الجداول، خذ نسخة احتياطية من قاعدة البيانات، وابنِ، وارفع الجداول إلى مستوى الكود الجديد قبل تشغيل واجهة API:

الطرفية
yarn build
yarn schema:prod
yarn start:prod
  • لا يكتب yarn schema:prod أي بيانات. يضيف ما هو جديد، ويحذف أيضًا العمود الذي لم يعد في الكود مع بياناته، لذلك تأتي النسخة الاحتياطية أولًا.
  • مع Docker تُترك وحدة التخزين الموجودة كما هي عند التشغيل. وحين تعمل الصورة الجديدة، طبّق المخطط فيها: docker compose exec -u node api node dist/database/schema.js (ومع docker run، docker exec -u node <container> node dist/database/schema.js).

البدء من البيانات التجريبية

كل عملية ملء بيانات تنشئ مساحات العمل التجريبية وأشخاصها، وتسجيلات الدخول الستة الموثقة وكل حساب تجريبي آخر بكلمة المرور المنشورة نفسها، وتملأ صورة Docker وحدة التخزين الجديدة بنفسها ما لم يكن SEED_SAMPLE_DATA=false. إذا بدأت من البيانات التجريبية، فاجعل التثبيت ملكك قبل أن يصبح متاحًا من الإنترنت:

  1. اجعل مسؤول المنصة التجريبي ملكك: سجّل الدخول بـ platform@northstack.example، وغيّر اسمه وبريده في «الإعدادات» ثم «الملف الشخصي»، وكلمة المرور في «الإعدادات» ثم «الأمان».
  2. لمساحة عملك الخاصة، أنشئ حسابًا في لوحة التحكم ببريدك أنت: ينشئ الإعداد الأولي مساحة العمل وتكون أنت مالكها. أو اجعل المالك التجريبي ملكك بالطريقة نفسها، وغيّر اسم Forma Studio في «الإعدادات» ثم «عام».
  3. في صفحة «المستخدمون» بالمنصة، احذف الحسابات التجريبية التي لا تحتاج إليها، أو استخدم تغيير كلمة المرور لأي حساب تُبقيه. يُرفض الحذف لحساب يملك مساحة عمل إلى أن يملكها عضو آخر (من صفحة «الفريق» في مساحة العمل تلك) أو تُحذف مساحة العمل («الإعدادات»، ثم «منطقة الخطر»).
  4. اضبط JWT_SECRET خاصًا بك، حتى يتوقف عمل رمز تسجيل دخول صُنع قبل التبديل.

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

الإطلاق

قبل أن يصبح Northstack متاحًا من الإنترنت:

  1. في بيئة واجهة API، NODE_ENV=production وJWT_SECRET طويل وعشوائي خاص بك (يولّد Docker واحدًا إذا لم يُضبط). في الإنتاج ترفض واجهة API أن تبدأ بالسر النموذجي أو من دون CORS_ORIGIN، وتذكر أي قيمة خاطئة.
  2. CORS_ORIGIN على الموقع ولوحة التحكم، وFRONTEND_URL وDASHBOARD_URL على لوحة التحكم، وWEBSITE_URL على الموقع، وPUBLIC_API_URL على واجهة API، وPUBLIC_MEDIA_URL على واجهة API متبوعة بـ /media.
  3. مفتاح Stripe الحي وويب هوك الخاص به على /api/billing/webhooks/stripe في عنوان واجهة API، مع STRIPE_WEBHOOK_SECRET: ومن دونه تذكر واجهة API ذلك في سجلها عند التشغيل وترفض كل إشعار، فلا تُسجَّل التجديدات ولا المدفوعات الفاشلة أبدًا. وفي PayPal، مفاتيح التطبيق الحي مع PAYPAL_ENV=live.
  4. الضريبة مضبوطة لبلدك: لا تفرض Northstack أي ضريبة بنفسها.
  5. إعدادات SMTP_*، وإلا لن يتلقى أحد الدعوات ولا إعادة تعيين بيانات الدخول ولا إيصالات التراخيص.
  6. قاعدة البيانات والملفات المرفوعة على تخزين دائم، مع نسخة احتياطية.
  7. فحص الصحة الخاص بالمضيف على /api/health، وTRUST_PROXY=1 خلف وكيل.
  8. بناء الواجهتين الأماميتين بقيم NEXT_PUBLIC_* العامة.
  9. علامتك التجارية في كل واجهة أمامية، والصفحات القانونية للموقع مكتوبة من جديد لعملك وبلدك.
  10. لا حسابات تجريبية: البدء فارغًا بـ yarn admin:create:prod أو SEED_SAMPLE_DATA=false، أو حذف الحسابات التجريبية أو تغيير كلمات مرورها، كما سبق.
  11. DEMO_MODE=false على واجهة API وNEXT_PUBLIC_DEMO_MODE=false في الواجهتين الأماميتين، كما تُشحن.

توقفت عند خطوة؟

ابحث عن الحل قبل أن تبدأ من جديد.

حل المشكلات

تفضيلات ملفات تعريف الارتباط

نستخدم ملفات تعريف الارتباط لتعزيز تجربة التصفح الخاصة بك وتحليل حركة المرور على الموقع وتخصيص المحتوى. بالنقر على "قبول الكل"، فإنك توافق على استخدامنا لملفات تعريف الارتباط للتحليلات والإعلانات المخصصة.