لماذا تستضيف Nuxt ذاتيًا على VPS؟
بفضل Nitro، يُنشئ Nuxt 3 بناءً قابلاً للنقل (preset: node-server) يبدأ كخادم Node بسيط يستمع على منفذ. وهذه القابلية للنقل مثالية لـVPS: تستفيد من التصيير من جهة الخادم ومن مسارات server/api ومن التخزين المؤقت للمسارات دون الاعتماد على بيئة تشغيل edge احتكارية.
تُلغي الاستضافة الذاتية حصص الدوال وتتيح لك ضبط التخزين المؤقت والضغط وعدد نسخ Node. ولتطبيق Vue 3 في الإنتاج مع مصادقة واستدعاءات API من الخادم وتحسين SEO متقَن، يوفّر VPS ثبات خادم دائم وتكلفة ثابتة، دون مفاجآت فاتورة حسب الاستدعاء.
فوائد ملموسة لاستضافة Nuxt ذاتيًا
- مسارات خادم
server/apiغير محدودة، دون فوترة لكل استدعاء. - SSR وعملية hydration الخاصة بـVue 3 تُقدَّمان من خادم Node دائم ومستقر.
- بناء Nitro قابل للنقل (
node-server) سهل التعبئة في حاوية وإعادة الإنتاج. - تخزين مؤقت للمسارات وقواعد
routeRules(SSR وSSG وISR وSWR) مُتحكَّم فيها من جهة الخادم. - توحيد عدة تطبيقات Nuxt على VPS واحد خلف Nginx.
- متغيرات بيئة وقت التشغيل (
runtimeConfig) تُدار مباشرة على خادمك الخاص. - تحكم كامل في ترويسات HTTP (CSP وHSTS وcache-control) عبر middleware في Nitro.
المتطلبات المسبقة للعتاد والبرمجيات
كما هو الحال مع أي إطار عمل حديث، يستهلك بناء Nuxt ذاكرة: استهدف 2 غيغابايت من ذاكرة RAM كحد أدنى (يمكن تنفيذ البناء في CI إذا كان VPS لديك أصغر). وعند وقت التشغيل، يكفي 1 vCPU و1 غيغابايت لخادم Nitro تحت حِمل خفيف؛ ارتقِ إلى 2 vCPU و2 غيغابايت للتطبيقات التي تحتوي على مسارات server/api متزامنة كثيرة.
ثبّت Node.js 20 LTS عبر nvm أو صورة node:20-alpine، إضافةً إلى PM2 للإشراف على العمليات. اضبط nitro: { preset: 'node-server' } في nuxt.config.ts. يلزم نطاق مُوجَّه نحو VPS للحصول على شهادة TLS. ويبقى Ubuntu 22.04 أو 24.04 LTS الأساس المُوصى به.
نشر Nuxt خطوة بخطوة
إعداد المشروع لـNode
حدِّد إعداد Nitro المسبق في
nuxt.config.ts:export default defineNuxtConfig({ nitro: { preset: 'node-server' } })عرِّف أسرارك في
runtimeConfigمن جهة الخادم حصرًا — وليس فيruntimeConfig.public. ومن جهة VPS، ثبّت Node.js 20 LTS عبرnvm install 20 && nvm use 20 && nvm alias default 20، ثم ثبّت PM2 بشكل عام:npm install -g 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=0.0.0.0 NITRO_PORT=3000لا تُدرج هذا الملف في المستودع أبدًا. تأكد من أنه مملوك للمستخدم الذي يُشغِّل PM2 وأنه قابل للقراءة من قِبَله وحده (
chmod 600).تشغيل خادم Nitro باستخدام PM2
ابدأ التطبيق واضبط التشغيل التلقائي:
pm2 start /srv/nuxt-app/.output/server/index.mjs \ --name nuxt-app \ --env-file /srv/nuxt-app/.env pm2 save pm2 startupتعرض الأمر
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 (وليس إعادة التشغيل) استمرارية الخدمة:cd /srv/nuxt-app git pull npm ci npm run build pm2 reload nuxt-appيُشغِّل PM2 الإصدار الجديد ويتحقق من استجابته ثم يُنهي القديم: صفر downtime. للتراجع، عد إلى الإيداع السابق وأعد البناء والتحميل. إذا جرى البناء في CI، انقل مجلد
.outputفقط عبر rsync وأعد التحميل دون إعادة البناء على الخادم.
تحسين التصيير باستخدام 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 + Traefik، git push يكفي | يتطلب Ruby، إعداد أولي أطول، مناسب للفرق |
استكشاف الأخطاء: مشكلات الإنتاج الشائعة
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. تأكد من استخدام --env-file عند بدء التشغيل وليس تصدير المتغيرات في الصدفة الحالية.
مسارات 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 الطلبات تلقائيًا بين العمال. اربط PM2 بأداة مثل Grafana عبر pm2-prometheus للتنبيه على عمليات إعادة التشغيل غير المتوقعة — وهي إشارة إلى خطأ أو تسريب ذاكرة يجب معالجته قبل أن يؤثر على المستخدمين.