نشر Laravel بنفسك، بلا الدقيقتين من الانقطاع
منصة مُدارة، أو خدمة تجهيز، أو خادم بسيط - والأمور الأربعة التي تقرر هل النشر غير مرئي، ولا واحد منها هو اختيار الاستضافة.
هناك ثلاث طرق معقولة لتشغيل تطبيق Laravel، والجدال حول أيّها يخفي عادةً أن سكربت النشر أهم من الاختيار.
الخيارات الثلاثة، بصدق
منصة مُدارة. تدفع، فتبني وتشغّل. أقل عمل تشغيلي متاح، بأعلى سعر للوحدة، مع قيود المنصة كقيودك أنت. جيدة لفريق بلا قدرة تشغيلية وحمل يتسع فيها.
خدمة تجهيز على خوادمك. شيء يضبط خادمًا تملكه ويعطيك نشرًا وشهادات وعمّالًا دون أن تكتب أنت الـ Ansible. هنا تعيش أغلب تطبيقات Laravel وهو افتراض معقول: تحتفظ بالجهاز، وتتخطى الإعداد.
خادم بسيط تضبطه بنفسك. الأرخص، وأكثر تحكمًا، وهو رخيص فقط إن ملكه أحد. التحديثات والشهادات والنسخ الاحتياطي والمراقبة - الفاتورة صغيرة والمسؤولية ليست.
لا يوجد جواب خطأ هنا. بل يوجد جواب بلا مالك.
ما يقرر فعلًا هل النشر يؤلم
١. إصدارات ذرّية. انشر في مجلد جديد وانقل رابطًا رمزيًا حين يجهز. ونسخ الملفات فوق تطبيق يعمل يعني أن الطلبات تُخدَم لثوانٍ من شيفرة نصف محدَّثة، ما ينتج أخطاءً لا يستطيع أحد إعادة إنتاجها بعدها.
releases/2026-09-21-140233/
current -> releases/2026-09-21-140233
المشترك بين الإصدارات: storage/ و.env. وكل ما عداه جديد في كل مرة، والرجوع
هو إعادة الرابط.
٢. إعادة بناء التخزين المؤقت، بالترتيب.
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cacheشغّلها على الإصدار الجديد قبل أن يصير الحالي. وconfig:cache خصوصًا تعني أن
env() تعيد null في كل مكان خارج ملفات الإعداد - وهو سلوك صحيح يفاجئ الناس،
فأبقِ env() في ملفات الإعداد وحدها.
٣. إعادة تشغيل عمّال الطوابير. الخطوة الأكثر غيابًا:
php artisan queue:restartالعامل يُقلع تطبيقك مرة ويحتفظ به. وبدون هذا تشغّل طبقة الويب الإصدار الجديد وتشغّل طبقة الطوابير ما كان حاليًا حين أقلعت تلك العمليات آخر مرة - وهي فئة أعطال قائمة بذاتها.
٤. الهجرات، مفصولة بحسب المخاطرة. الروتينية في النشر. وكل ما يعيد كتابة جدول كبير يُشغَّل متعمَّدًا ومراقَبًا، لأن القفل يدوم أطول من مهلة الطلب وسيبلّغ النشر عن نجاح بينما يعيد الموقع أخطاءً.
الترتيب الذي يبقي الموقع قائمًا
# في مجلد الإصدار الجديد، قبل أن يصير حيًّا
composer install --no-dev --optimize-autoloader
npm ci && npm run build
php artisan config:cache && php artisan route:cache && php artisan view:cache
# اجعله الحالي
ln -sfn "$RELEASE" current
# بعده
php artisan migrate --force
php artisan queue:restart
sudo systemctl reload php8.3-fpmأعد التحميل بدل إعادة التشغيل، لتنتهي الطلبات الجارية. وتحقق بعدها بدل الثقة بالسكربت:
ps -eo lstart,cmd | grep "[q]ueue:work"أوقات بدء أقدم من النشر تعني أن إعادة التشغيل لم تصلهم.
الأجزاء التي ينسى الناس إعدادها أصلًا
المجدول يحتاج مدخل cron واحدًا، واحدًا فقط، على جهاز واحد:
* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1
خادمان يشغّلانه يعني أن كل مهمة مجدولة تعمل مرتين.
العمّال يحتاجون مشرفًا. الأمر queue:restart يوقف العمّال؛ ولا يبدؤهم. وبلا
systemd أو Supervisor يراقب، يتركك النشر بصمت بلا أي عامل وتتكدس المهام حتى
يلاحظ أحد.
النسخ الاحتياطية تحتاج استرجاعًا. النسخة التي لم تُسترجع قط فرضية. استرجع واحدة في بيئة اختبار، بانتظام، واكتب كم استغرقت - ذلك الرقم هو زمن تعافيك الفعلي.
السجلات تحتاج وجهة. الملف اليومي الافتراضي على خادم التطبيق يكفي حتى يصير لديك خادمان، وعندها يعني الحادث قراءة مجموعتي ملفات يدويًا.
الجزء الذي لا يتعلق بالاستضافة
لا شيء مما سبق يعتمد على أي الخيارات الثلاثة اخترت. المنصة المُدارة تتولى بعضه عنك؛ والخادم البسيط يعني أنك تكتبه مرة. وفي الحالتين إما أن يعيد النشر تشغيل العمّال وإما لا.
ولهذا فأنفع ما تفعله بهذا المقال ليس تغيير الاستضافة. بل قراءة سكربت نشرك ومعرفة أي هذه الخطوات الأربع ناقص - وفي تجربتنا هو إعادة تشغيل العمّال عادةً، وهو ناقص منذ اليوم الذي كُتب فيه السكربت.
