لماذا تستضيف Nuxt ذاتيًا على VPS؟
بفضل Nitro، يُنشئ Nuxt بناءً قابلًا للنقل (preset: node-server) يبدأ كخادم Node بسيط يستمع على منفذ. وهذه القابلية للنقل مثالية لـVPS: تستفيد من التصيير من جهة الخادم ومن مسارات server/api ومن التخزين المؤقت للمسارات دون الاعتماد على بيئة تشغيل edge احتكارية.
تُلغي الاستضافة الذاتية حصص الدوال وتتيح لك ضبط التخزين المؤقت والضغط وعدد نسخ Node. ولتطبيق Vue 3 في الإنتاج مع مصادقة واستدعاءات API من الخادم وتحسين SEO متقَن، يوفّر VPS ثبات خادم دائم وتكلفة ثابتة، دون مفاجآت فاتورة حسب الاستدعاء.
لكن ذلك يتطلّب خادمًا يقبل عملية Node.js دائمة، وأغلب الاستضافات المشتركة لا تسمح بها، ما يستبعد SSR ومسارات الخادم من البداية. على VPS تختار أيضًا إصدار Node.js والوكيل العكسي (Nginx أو Caddy) وطريقة إدارة شهادات TLS، دون سقف مصطنع على المعالج أو الذاكرة.
فوائد ملموسة لاستضافة Nuxt ذاتيًا
- مسارات خادم
server/apiغير محدودة، دون فوترة لكل استدعاء. - SSR وعملية hydration الخاصة بـVue 3 تُقدَّمان من خادم Node دائم ومستقر.
- بناء Nitro قابل للنقل (
node-server) سهل التعبئة في حاوية وإعادة الإنتاج. - تخزين مؤقت للمسارات وقواعد
routeRules(SSR وSSG وISR وSWR) مُتحكَّم فيها من جهة الخادم. - عدّة تطبيقات Nuxt على VPS واحد خلف Nginx، لكلّ منها منفذ داخلي خاص (3000 و3001…).
- متغيرات بيئة وقت التشغيل (
runtimeConfig) تُدار مباشرة على خادمك الخاص. - تحكم كامل في ترويسات HTTP (CSP وHSTS وcache-control) عبر middleware في Nitro.
- موقع مولَّد مسبقًا بالأمر
nuxt generateيقدّمه Nginx وحده، دون عملية Node.js دائمة.
SSR أم SSG أم SPA أم الهجين: أيّ نمط تصيير تختار؟
مرّر الجدول أفقيًا
| النمط | التصيير | عملية Node.js | الأنسب لـ |
|---|---|---|---|
| SSR (افتراضي) | عند كل طلب، من جهة الخادم | نعم، يشرف عليها PM2 | تطبيق ديناميكي، SEO، محتوى مخصّص |
| SSG (`nuxt generate`) | أثناء البناء، بصيغة HTML ثابتة | لا، يقدّم Nginx المجلّد `.output/public` | مدوّنة، موقع تعريفي، محتوى قليل التغيّر |
| SPA (`ssr: false` + `nuxt generate`) | داخل المتصفّح | لا، يكفي Nginx | لوحة تحكّم داخلية، تطبيق خلف المصادقة |
| هجين (`routeRules`) | حسب المسار: SSR، توليد مسبق، SWR، ISR | نعم، خادم Nitro | تطبيق يجمع صفحات ثابتة ومسارات API |
المتطلبات المسبقة للعتاد والبرمجيات
كما هو الحال مع أيّ إطار عمل حديث، يستهلك بناء Nuxt الذاكرة: استهدف 2 غيغابايت من RAM على الأقل (يمكن تنفيذ البناء في CI إن كان VPS متواضعًا). أثناء التشغيل يكفي معالج افتراضي واحد و1 غيغابايت لخادم Nitro تحت حمل خفيف؛ ارفع إلى 2 vCPU و2 غيغابايت للتطبيقات ذات مسارات server/api المتزامنة الكثيرة، وإلى 2 vCPU و4 غيغابايت إن تقاسمت عدّة تطبيقات Nuxt الخادم نفسه.
أما الإصدارات، فابدأ من Nuxt 4: بلغ Nuxt 3 نهاية عمره في 31 يوليو 2026 ولم يعد يتلقّى إصلاحات ولا تحديثات أمنية. والنشر الموصوف هنا واحد في الإصدارين، لأن Nitro هو من يُنتج الخادم. ثبّت خطّ LTS من Node.js ما زال مدعومًا، أي Node.js 24 أو 26 (انتهى دعم Node.js 20 في 30 أبريل 2026)، عبر nvm أو صورة node:24-alpine، مع PM2 للإشراف على العمليات. node-server هو الإعداد المسبق الذي يطبّقه Nitro افتراضيًا على بناء الإنتاج، وذكره في nuxt.config.ts يجعله صريحًا فحسب. يلزم نطاق يشير إلى VPS للحصول على شهادة TLS. ويبقى Ubuntu 22.04 أو 24.04 LTS القاعدة الموصى بها.
الانطلاق من قالب Nuxt Stack
يجهّز قالب Nuxt Stack في Marketplace الخاص بـ ServOrbit خادم VPS بنظام Ubuntu 24.04 مع Node.js من خطّ LTS الحالي في مستودع NodeSource، وPM2 مثبّتًا على مستوى النظام، وNginx، وPostgreSQL. يعفيك القالب من تثبيت بيئة التشغيل، فتبدأ الخطوات التالية عندئذٍ من تهيئة المشروع.
هذه بيئة تشغيل وليست تطبيقًا بشاشة تسجيل دخول: تدخلها عبر SSH (ssh root@<vps-ip>) لرفع شيفرتك. عند الدخول الأول يعرض Nginx صفحته الافتراضية على المنفذ 80، ويبقى عليك إعداد virtual host لتطبيقك وشهادة Let's Encrypt (فـ Certbot غير مثبّت مسبقًا) ورفع شيفرتك. لا يستمع PostgreSQL إلا محليًا، بمصادقة peer لمستخدم النظام postgres (sudo -u postgres psql)، وهذا يكفي لربط DATABASE_URL بالعنوان 127.0.0.1 دون كشف قاعدة البيانات.
نشر Nuxt خطوة بخطوة
إعداد المشروع لـNode
حدِّد إعداد Nitro المسبق في
nuxt.config.ts:export default defineNuxtConfig({ nitro: { preset: 'node-server' } })عرِّف أسرارك في
runtimeConfigمن جهة الخادم حصرًا — وليس فيruntimeConfig.public. ومن جهة VPS، ثبّت Node.js 24 LTS عبرnvm install 24 && nvm use 24 && nvm alias default 24، ثم ثبّت PM2 على مستوى النظام:npm install -g pm2. في قالب Nuxt Stack يكون Node.js وPM2 مثبّتين مسبقًا.بناء التطبيق
استنسخ المستودع وثبّت الاعتماديات:
git clone https://git.yourdomain.com/your-org/your-app.git /srv/nuxt-app cd /srv/nuxt-app npm ci npm run buildينتج Nitro مجلدًا مستقلًا
.outputيحتوي علىserver/index.mjsوالأصول الثابتة في.output/public. وهذا المجلد هو كل ما يحتاجه VPS لتقديم التطبيق في الإنتاج — يمكنك أيضًا تجميعه في CI ونقله عبر rsync لتجنب البناء على الخادم.إنشاء ملف البيئة
أنشئ الملف
/srv/nuxt-app/.envمع متغيرات وقت التشغيل. كل متغير مسبوق بـNUXT_يُلغي المفتاح المقابل فيruntimeConfigعند بدء التشغيل:NUXT_MY_SECRET_KEY=production-value NITRO_HOST=127.0.0.1 NITRO_PORT=3000لا تُدرج هذا الملف في المستودع أبدًا. تأكد من أنه مملوك للمستخدم الذي يُشغِّل PM2 وأنه قابل للقراءة من قِبَله وحده (
chmod 600).مع
NITRO_HOST=127.0.0.1لا يستمع Nitro إلا على الواجهة المحلية: لا يصل إليه سوى Nginx، ولا يُكشف المنفذ 3000 على الإنترنت.تشغيل خادم Nitro باستخدام PM2
شغّل التطبيق في وضع cluster مع مطالبة Node بتحميل ملف البيئة: لا يقرأ Nuxt ملف
.envفي الإنتاج، وليس في سطر أوامر PM2 خيار مخصّص لذلك.pm2 start /srv/nuxt-app/.output/server/index.mjs \ --name nuxt-app -i max \ --node-args="--env-file=/srv/nuxt-app/.env" pm2 save pm2 startupيطلق الخيار
-i maxنسخة لكل vCPU، ووضع cluster هذا هو ما يتيح إعادة التحميل دون انقطاع في الخطوة الأخيرة. يعرض الأمرpm2 startupسطرًا للنسخ واللصق لإنشاء خدمة systemd. نفِّذه بصلاحيات المدير. تحقَّق من أن التطبيق يعمل: يجب أن يُظهرpm2 statusالحالةonline.إعداد Nginx كبروكسي عكسي
أنشئ الملف
/etc/nginx/sites-available/nuxt-app:server { listen 80; server_name yourdomain.com www.yourdomain.com; location /_nuxt/ { root /srv/nuxt-app/.output/public; expires 1y; add_header Cache-Control "public, immutable"; } location /favicon.ico { root /srv/nuxt-app/.output/public; } location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header 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_cache_bypass $http_upgrade; } }فعِّل الموقع واختبر الإعداد:
ln -s /etc/nginx/sites-available/nuxt-app /etc/nginx/sites-enabled/ && nginx -t && systemctl reload nginx.تفعيل HTTPS باستخدام Let's Encrypt
ثبّت Certbot وإضافة Nginx، ثم أنشئ الشهادة:
apt install certbot python3-certbot-nginx certbot --nginx -d yourdomain.com -d www.yourdomain.comيُعدِّل Certbot تلقائيًا كتلة Nginx للاستماع على المنفذ 443 وفرض إعادة التوجيه من HTTP إلى HTTPS. تحقَّق من أن
X-Forwarded-Protoيُمرَّر بشكل صحيح إلى Nitro — بدونه قد يتصرفuseRequestHeaders()من جهة الخادم وعمليات إعادة التوجيه القائمة على البروتوكول بشكل خاطئ. يتولى مؤقت systemd الخاص بـCertbot التجديد التلقائي، ويمكن التحقق منه بـsystemctl status certbot.timer.التحديث دون انقطاع الخدمة
للتحديث، يضمن
reloadفي PM2 (وليس إعادة التشغيل) استمرارية الخدمة. اجمع الأوامر في سكربت/srv/nuxt-app/deploy.sh، يوقفهset -eعند أول خطأ قبل أيّ إعادة تحميل:#!/bin/bash set -e cd /srv/nuxt-app git pull origin main npm ci npm run build pm2 reload nuxt-appاجعله قابلًا للتنفيذ (
chmod +x deploy.sh) واستدعِه من خطّ CI/CD عبر SSH. في وضع cluster يستبدل PM2 النسخ واحدة تلو الأخرى، فيتسلّم الإصدار الجديد قبل أن يتوقّف القديم. للتراجع، عد إلى الإيداع السابق وأعد البناء والتحميل. إذا جرى البناء في CI، انقل مجلد.outputفقط عبر rsync وأعد التحميل دون إعادة البناء على الخادم.
متغيّرات البيئة: العامة والخاصة وإعادة التحميل
يرتّب Nuxt إعدادات التشغيل على مستويين. المفاتيح الموضوعة تحت runtimeConfig.public تُرسَل إلى المتصفّح وتبقى مقروءة من جهة الخادم، مثل عنوان API العام أو معرّف قياس الجمهور. أما باقي مفاتيح runtimeConfig فلا تغادر الخادم أبدًا، مثل المفاتيح السرّية وبيانات الوصول إلى قاعدة البيانات.
عند الإقلاع، يحلّ متغيّر البيئة محلّ المفتاح المقابل إن اتّبع اصطلاح NUXT_<NAME>، أو NUXT_PUBLIC_<NAME> للمفتاح العام: فالمتغيّر NUXT_PUBLIC_API_BASE يحلّ محلّ runtimeConfig.public.apiBase. أما القيمة المقروءة من مصدر آخر، مثل process.env.OTHER_VARIABLE المكتوبة في nuxt.config.ts، فلا تُؤخذ إلا أثناء البناء وتبقى مجمّدة في الحزمة.
عمليًا، لا يتطلّب تغيير عنوان API أو مفتاح إعادة البناء: تعدّل ملف .env على الخادم ثم تعيد تحميل PM2 (pm2 reload nuxt-app). وهكذا يمكن للمجلّد .output نفسه أن يخدم بيئة ما قبل الإنتاج والإنتاج بملفّي بيئة مختلفين. الشرط الوحيد أن تحمّل العملية هذا الملف، لأن Nuxt لا يقرأ .env بعد بناء التطبيق، ومن هنا الخيار --env-file المُمرَّر إلى Node عند الإطلاق مع PM2.
تحسين التصيير باستخدام routeRules
إحدى نقاط قوة Nuxt على VPS هي دقة استراتيجيات التصيير لكل صفحة على حدة، دون تغيير البنية التحتية. في nuxt.config.ts، تتيح لك routeRules مزج SSR وSSG وISR وSWR في نشر Nitro واحد.
يمكن لصفحات المدونة والصفحات القانونية والصفحات الهبوطية أن تُولَّد مسبقًا عند البناء باستخدام prerender: true: يقدمها Nitro من القرص دون الحاجة إلى Node. تستفيد الصفحات شبه الديناميكية (قوائم المنتجات ولوحات التحكم العامة) من swr: 60 للحصول على ذاكرة تخزين مؤقت مدتها دقيقة واحدة تُبطَل في الخلفية. يبقى SSR الكامل للصفحات الشخصية التي تعتمد على الجلسة أو ملف المستخدم.
يُقلل هذا النهج الحِمل على Node دون الحاجة إلى شبكة CDN مدفوعة أو طبقة تخزين مؤقت خارجية — يخزن Nginx ما يُولِّده Nitro مسبقًا.
Nitro server مقابل Docker مقابل Vercel/Netlify لاستضافة Nuxt
مرّر الجدول أفقيًا
| النهج | المزايا | القيود |
|---|---|---|
| Nitro `node-server` + PM2 | بسيط وخفيف، إعادة تحميل بدون توقف، تكلفة VPS ثابتة | إشراف يدوي، خادم واحد بدون توفر عالٍ أصلي |
| Docker على VPS | عزل، قابلية إعادة الإنتاج، التراجع بالصورة، compose لتطبيقات متعددة | صورة للبناء والتخزين، ذاكرة إضافية لكل حاوية |
| Vercel / Netlify | إعداد صفري، CDN عالمي، معاينات لكل PR | حصص الدوال، تكلفة متغيرة، لا تحكم في البنية التحتية |
| Kamal (نشر بدون توقف) | ينسّق Docker وkamal-proxy، نشر بأمر واحد (`kamal deploy`) | أداة Ruby (gem أو صورة Docker)، إعداد أولي أطول، مناسب للفرق |
السجلّات: قراءتها وتدويرها ومقارنتها بسجلّات Nginx
يجمع PM2 مخرجات التطبيق: يتابع الأمر pm2 logs nuxt-app التدفّق مباشرة (المخرجات القياسية والأخطاء)، ويعرض pm2 logs nuxt-app --lines 100 آخر الأسطر. تُكتب الملفات في ~/.pm2/logs/، بملف -out.log وملف -error.log لكل تطبيق، مع رقم النسخة لاحقةً في وضع cluster.
لا تُدوَّر هذه الملفات من تلقاء نفسها. تدوّرها الوحدة pm2-logrotate بعد 10 ميغابايت وتحتفظ افتراضيًا بثلاثين نسخة؛ عدّل هذه العتبات بحسب حجم قرصك:
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 7حين يتلقّى المتصفّح خطأ 502 أو 504، ابدأ بالنظر من جهة Nginx: يخبرك /var/log/nginx/error.log إن كان قد عجز عن الوصول إلى 127.0.0.1:3000 (عملية متوقّفة أو منفذ خاطئ) أو إن كان Nitro قد تأخّر كثيرًا في الردّ.
استكشاف الأخطاء: مشكلات الإنتاج الشائعة
Error: listen EADDRINUSE: address already in use :::3000
عملية ما تشغل المنفذ 3000 بالفعل. حدِّدها بـss -tlnp | grep 3000 وأوقف نسخة PM2 اليتيمة: pm2 delete nuxt-app ثم إعادة تشغيل نظيفة. تجنب تشغيل نسخ متعددة بلا load balancer — استخدم cluster_mode في PM2.
502 Bad Gateway في Nginx
Nitro غير مُشغَّل أو يستمع على منفذ خاطئ. تحقَّق من pm2 status وراجع السجلات: pm2 logs nuxt-app --lines 50. تحقَّق أيضًا من أن التوجيه proxy_pass في Nginx يُشير إلى http://127.0.0.1:3000 (وليس localhost الذي قد يُحلَّل إلى IPv6 إذا كانت العملية تستمع على IPv4 فقط).
useRuntimeConfig() تُعيد undefined
لا تُقرأ متغيّرات NUXT_* إلا عند بدء عملية Nitro: بعد تعديل .env أعد التحميل بالأمر pm2 reload nuxt-app. تحقّق من أن الملف يُحمَّل فعلًا عبر --node-args="--env-file=…" وليس مُصدَّرًا في الصدفة الحالية التي تختفي بانتهاء جلسة SSH. وإن كانت القيمة غائبة في المتصفّح وحده، فيجب تعريف المفتاح تحت runtimeConfig.public وأن يبدأ المتغيّر بالبادئة NUXT_PUBLIC_.
مسارات server/api تُعيد 404 في الإنتاج
تحقَّق من أن البناء يتضمن مجلد server/ في .output. إعداد nitro.preset الخاطئ (مثلًا static بدلًا من node-server) يُولِّد موقعًا ثابتًا بلا خادم. أعد البناء بـnpm run build بعد التحقق من nuxt.config.ts.
X-Forwarded-Proto متجاهَل، حلقة إعادة توجيه
إذا كان Nuxt يُعيد التوجيه من HTTP إلى HTTPS في حلقة، فذلك يعني أن middleware إعادة التوجيه يرى http رغم HTTPS من جهة العميل. تأكد من أن Nginx يُمرِّر proxy_set_header X-Forwarded-Proto $scheme وأن nuxt.config.ts لا يفرض إعادة توجيه HTTPS مرتين مع Certbot.
المراقبة والمقاييس باستخدام PM2
يتيح PM2 لوحة تحكم زمنية حقيقية بـpm2 monit: المعالج والذاكرة وعمليات إعادة التشغيل وسجلات العمليات. لتطبيق Nuxt تحت حِمل، فعِّل وضع cluster لاستخدام جميع vCPU المتاحة:
pm2 start .output/server/index.mjs --name nuxt-app -i maxيوزِّع PM2 الطلبات تلقائيًا بين العمال. صدِّر هذه المقاييس إلى Prometheus وGrafana لتتلقّى تنبيهًا عند عمليات إعادة التشغيل غير المتوقعة — وهي إشارة إلى خطأ أو تسريب ذاكرة يجب معالجته قبل أن يؤثر على المستخدمين.
التوثيق الرسمي
للإعدادات المتقدّمة وتغييرات الإصدارات، ارجع إلى التوثيق الرسمي لـ Nuxt (routeRules وruntimeConfig والوحدات)، وإلى صفحة Node.js في توثيق Nitro لمعرفة المتغيّرين NITRO_PORT وNITRO_HOST، وإلى توثيق وضع cluster في PM2. يغطّي هذا الدليل الإطلاق على VPS، ويبقى توثيق الناشر المرجع في الضبط الدقيق.