تخطى إلى المحتوى
·12 دقيقة قراءة

إعداد VPS الذي يعمل فعلا: Node.js و PM2 و Nginx ونشر بدون توقف

إعداد نشر VPS الدقيق الذي أستخدمه في بيئة الإنتاج — تقوية Ubuntu، وضع المجموعات في PM2، وكيل عكسي Nginx، SSL، وسكريبت نشر لم يخذلني بعد. لا نظريات، فقط ما يعمل.

مشاركة:X / TwitterLinkedIn

هذه المدونة تعمل على VPS بـ 10 دولارات/شهر. ليس Vercel، ليس AWS، ليس مجموعة Kubernetes يديرها فريق من ستة أشخاص. صندوق Ubuntu واحد مع Nginx و PM2 وسكريبت bash ينشر في أقل من 30 ثانية.

جربت المسارات الأخرى. استخدمت Vercel (رائع حتى تحتاج وظائف مجدولة أو WebSockets مستمرة أو مجرد تحكم). استخدمت AWS (رائع إذا كنت تستمتع بقضاء نصف يومك في سياسات IAM). دائما أعود إلى VPS.

لكن إليك المشكلة: كل دليل "انشر على VPS" على الإنترنت يتوقف عند المسار السعيد. يُريك كيف تثبت Node.js وتشغل node server.js ويسميها إنتاج. ثم يتعرض خادمك لهجوم القوة الغاشمة على SSH، وتموت عمليتك في الساعة 3 صباحا لأن لا أحد أعد مدير عمليات، وشهادة SSL انتهت صلاحيتها منذ ثلاثة أشهر.

هذا هو الدليل الذي كنت أتمنى لو كان لدي. كل شيء هنا مُختبر في المعركة — هذا الإعداد بالذات يخدم الصفحة التي تقرأها الآن.

ابدأ بالأمان، وليس الكود#

قبل أن تفكر حتى في Node.js، أمّن الصندوق. مثيلات VPS الجديدة هي أهداف. الروبوتات الآلية تبدأ بضرب منفذ SSH في غضون دقائق من التوفير.

أنشئ مستخدما غير الجذر#

bash
adduser deploy
usermod -aG sudo deploy

إعداد مصادقة مفتاح SSH#

على جهازك المحلي:

bash
ssh-copy-id deploy@your-server-ip

ثم عطّل مصادقة كلمة المرور بالكامل:

bash
sudo nano /etc/ssh/sshd_config
bash
PasswordAuthentication no
PermitRootLogin no
bash
sudo systemctl restart sshd

إذا تخطيت هذا، سترى آلاف محاولات تسجيل الدخول الفاشلة في سجلات المصادقة في غضون أيام. هذه ليست جنون ارتياب — إنه يوم عادي على الإنترنت العام.

جدار الحماية مع UFW#

bash
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

هذا كل شيء. أربع قواعد. فقط حركة SSH والويب تمر.

Fail2Ban#

bash
sudo apt install fail2ban -y
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

عدّل /etc/fail2ban/jail.local:

ini
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
bash
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

ثلاث محاولات SSH فاشلة وتُحظر لمدة ساعة. شاهدت Fail2Ban يحظر مئات عناوين IP في يوم واحد. إنه يعمل.

تحديثات الأمان التلقائية#

bash
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades

خادمك الآن سيثبت تصحيحات الأمان تلقائيا. شيء أقل لتنساه.

Node.js: استخدم NVM، وليس apt#

أرى هذا في كل دليل: sudo apt install nodejs. لا تفعل ذلك.

مستودعات حزم Ubuntu تشحن إصدارات Node.js قديمة. حتى PPA من NodeSource يتأخر. وعندما تحتاج للتبديل بين Node 20 و Node 22 لمشاريع مختلفة، أنت عالق.

NVM يحل هذا:

bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install --lts
nvm alias default lts/*

الآن تحقق:

bash
node -v  # v22.x.x أو أيا كان LTS الحالي
npm -v

النصيحة غير الواضحة: عندما تثبت حزما عامة مع NVM (مثل PM2)، تكون مرتبطة بذلك الإصدار من Node. إذا غيرت الإصدارات بـ nvm use، تختفي حزمك العامة. عيّن الافتراضي والتزم به على الخادم:

bash
nvm alias default 22

حدث هذا معي مرة واحدة بالضبط. مرة واحدة كانت كافية.

PM2: مدير العمليات الذي يستحق مكانه#

PM2 هو الفرق بين "منشور" و "جاهز للإنتاج". يتعامل مع إدارة العمليات والتجميع وتدوير السجلات وإعادة التشغيل التلقائي عند الأعطال وسكريبتات بدء التشغيل. مجانا.

التثبيت والإعداد#

bash
npm install -g pm2

إعداد النظام البيئي#

لا تبدأ التطبيقات بعلامات سطر الأوامر. استخدم ملف ecosystem.config.js. إنه خاضع لتحكم الإصدارات وقابل للتكرار وموثق ذاتيا.

javascript
// ecosystem.config.js
module.exports = {
  apps: [
    {
      name: "akousa",
      script: "node_modules/.bin/next",
      args: "start -p 3002",
      cwd: "/var/www/akousa.net",
      instances: 2,
      exec_mode: "cluster",
      max_memory_restart: "500M",
      env: {
        NODE_ENV: "production",
        PORT: 3002,
      },
      // إيقاف رشيق
      kill_timeout: 5000,
      listen_timeout: 10000,
      wait_ready: false,
      // التسجيل
      log_date_format: "YYYY-MM-DD HH:mm:ss Z",
      error_file: "/var/log/pm2/akousa-error.log",
      out_file: "/var/log/pm2/akousa-out.log",
      merge_logs: true,
      // إعادة التشغيل التلقائي عند الفشل
      autorestart: true,
      max_restarts: 10,
      min_uptime: "10s",
      // لا تراقب في بيئة الإنتاج
      watch: false,
    },
  ],
};

دعني أشرح الخيارات المهمة:

instances: 2 بدلا من "max": على VPS صغير بنواة واحدة أو اثنتين، "max" يبدو ذكيا لكنه سيولد عمليات تتصارع على الموارد أثناء البناء. مثيلان يعطيانك إعادة تحميل بدون توقف مع ترك هامش. على آلة بـ 4+ أنوية، بالتأكيد استخدم "max".

exec_mode: "cluster": هذا ما يُمكّن إعادة التحميل بدون توقف. بدون وضع المجموعات، pm2 reload هو مجرد إعادة تشغيل أنيقة. مع وضع المجموعات، يُعيد PM2 تشغيل المثيلات واحدة تلو الأخرى — تطبيقك لا يتوقف أبدا بالكامل.

max_memory_restart: "500M": تطبيق Next.js لديه تسرب ذاكرة؟ PM2 سيعيد تشغيله قبل أن يقتل الخادم بنفاد الذاكرة. أنقذني هذا من تنبيهات الساعة 2 صباحا أكثر من مرة.

kill_timeout: 5000: يعطي تطبيقك 5 ثوان لإنهاء الطلبات الجارية قبل أن يقتله PM2 بالقوة. الافتراضي (1600 ملي ثانية) عنيف جدا للتطبيقات ذات اتصالات قاعدة البيانات.

watch: false: رأيت أشخاصا يتركون watch: true في بيئة الإنتاج. PM2 حينها يُعيد تشغيل التطبيق كلما تغير ملف سجل. تطبيقك يدخل حلقة إعادة تشغيل. لا تفعل ذلك.

سكريبت بدء التشغيل#

اجعل PM2 ينجو من إعادة التشغيل:

bash
pm2 startup systemd
# انسخ وشغّل الأمر الذي يُخرجه
pm2 save

هذا يولد خدمة systemd. بعد إعادة تشغيل الخادم، يعود تطبيقك تلقائيا. اختبره — أعد تشغيل خادمك وتحقق. لا تفترض.

تدوير السجلات#

السجلات ستأكل قرصك في النهاية. ثبّت وحدة التدوير:

bash
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 7
pm2 set pm2-logrotate:compress true

50 ميغابايت حد أقصى لكل ملف، احتفظ بـ 7 ملفات مُدوّرة، اضغط القديمة. بدون هذا، رأيت /var/log يملأ قرصا بـ 25 غيغابايت في ثلاثة أسابيع على تطبيق بحركة معتدلة.

Nginx: الوكيل العكسي الذي يفعل أكثر مما تظن#

"لماذا لا تكشف Node.js مباشرة على المنفذ 80؟"

لأن Nginx يتعامل مع أشياء لا يجب أن يهدر Node.js دوراته عليها: إنهاء SSL، تقديم الملفات الثابتة، ضغط gzip، تخزين الطلبات المؤقت، حدود الاتصالات، والتعامل الرشيق مع العملاء البطيئين. مكتوب بـ C ومصمم خصيصا لهذا.

التثبيت#

bash
sudo apt install nginx -y

الإعداد#

nginx
# /etc/nginx/sites-available/akousa.net
 
upstream node_app {
    server 127.0.0.1:3002;
    keepalive 64;
}
 
server {
    listen 80;
    listen [::]:80;
    server_name akousa.net www.akousa.net;
 
    # إعادة توجيه كل HTTP إلى HTTPS
    return 301 https://$host$request_uri;
}
 
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name akousa.net www.akousa.net;
 
    # SSL (يُدار بواسطة Certbot — تُضاف هذه الأسطر تلقائيا)
    ssl_certificate /etc/letsencrypt/live/akousa.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/akousa.net/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
 
    # ترويسات الأمان
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
 
    # ضغط Gzip
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_min_length 256;
    gzip_types
        text/plain
        text/css
        text/javascript
        application/javascript
        application/json
        application/xml
        image/svg+xml
        application/wasm;
 
    # إعدادات الوكيل
    location / {
        proxy_pass http://node_app;
        proxy_http_version 1.1;
 
        # الترويسات
        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;
 
        # دعم WebSocket (إذا احتجته يوما)
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
 
        # المهل الزمنية — سخية لكن ليست لا نهائية
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
 
        # التخزين المؤقت — دع Nginx يتعامل مع العملاء البطيئين
        proxy_buffering on;
        proxy_buffer_size 16k;
        proxy_buffers 4 32k;
        proxy_busy_buffers_size 64k;
    }
 
    # أصول Next.js الثابتة — دع Nginx يقدمها مباشرة
    location /_next/static/ {
        alias /var/www/akousa.net/.next/static/;
        expires 365d;
        access_log off;
        add_header Cache-Control "public, immutable";
    }
 
    # الملفات الثابتة العامة
    location /static/ {
        alias /var/www/akousa.net/public/static/;
        expires 30d;
        access_log off;
    }
 
    # حظر الوصول إلى ملفات النقطة
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

فعّله:

bash
sudo ln -s /etc/nginx/sites-available/akousa.net /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

شغّل دائما nginx -t قبل إعادة التحميل. ذات مرة دفعت إعدادا معطلا وأوقفت الموقع لأنني تخطيت فحص الصياغة. الأحرف الخمسة nginx -t كانت ستوفر عليّ ثلاثين دقيقة من التصحيح المذعور.

أشياء تفوتها معظم الأدلة في هذا الإعداد:

كتلة upstream مع keepalive 64: Nginx يعيد استخدام الاتصالات بخلفية Node.js بدلا من فتح اتصال TCP جديد لكل طلب. هذا مهم تحت الحمل.

proxy_buffering on: Nginx يقرأ الاستجابة بالكامل من Node.js إلى الذاكرة، ثم يرسلها إلى العميل بأي سرعة يستطيع العميل استقبالها. بدون هذا، عميل بطيء على اتصال 3G يحجز عامل Node.js الخاص بك.

تقديم _next/static/ مباشرة: هذه أصول مُجزّأة وغير قابلة للتغيير. دع Nginx يقدمها من القرص بترويسة تخزين مؤقت لمدة 365 يوما. عمليات Node.js الخاصة بك لا يجب أن تهدر وقتها على هذا.

SSL في خمس دقائق#

Let's Encrypt حلت مشكلة SSL. إذا كنت لا تزال تدفع مقابل الشهادات في 2026، توقف.

bash
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d akousa.net -d www.akousa.net

Certbot سيسألك عن بريدك الإلكتروني، يقبل شروط الخدمة، ويعدل إعداد Nginx تلقائيا ليتضمن توجيهات SSL. هذا كل شيء.

التحقق من التجديد التلقائي#

Certbot يثبت مؤقت systemd يتحقق مرتين يوميا ويجدد الشهادات في غضون 30 يوما من انتهاء الصلاحية:

bash
sudo systemctl list-timers | grep certbot

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

bash
sudo certbot renew --dry-run

إذا نجح الاختبار، لن تفكر في SSL مرة أخرى. إذا فشل، عادة لأن المنفذ 80 محظور (تحقق من قواعد UFW) أو Nginx لا يعمل.

شيء اكتشفته: إذا أعددت Nginx قبل تشغيل Certbot، تأكد أن كتلة الخادم تستمع على المنفذ 80 بدون إعادة توجيه HTTPS أولا. Certbot يحتاج الوصول إلى المنفذ 80 لتحدي HTTP-01. بعد تشغيل Certbot بنجاح، عندها أضف إعادة التوجيه.

سكريبت النشر#

هذا هو السكريبت الذي يعمل كل مرة أدفع فيها إلى بيئة الإنتاج. لا منصة CI/CD، لا GitHub Actions. فقط SSH و bash.

bash
#!/bin/bash
# deploy.sh — نشر بدون توقف تقريبا
 
set -euo pipefail
 
APP_DIR="/var/www/akousa.net"
APP_NAME="akousa"
LOG_FILE="/var/log/deploy.log"
HEALTH_URL="http://localhost:3002"
MAX_RETRIES=10
RETRY_INTERVAL=3
 
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
 
log "=== Deploy started ==="
 
cd "$APP_DIR"
 
# سحب أحدث الكود
log "Pulling latest changes..."
git pull origin main 2>&1 | tee -a "$LOG_FILE"
 
# تثبيت التبعيات
log "Installing dependencies..."
npm install --legacy-peer-deps 2>&1 | tee -a "$LOG_FILE"
 
# البناء
log "Building application..."
rm -rf .next
npm run build 2>&1 | tee -a "$LOG_FILE"
 
if [ $? -ne 0 ]; then
    log "ERROR: Build failed. Aborting deploy."
    exit 1
fi
 
# إعادة تحميل PM2 (بدون توقف في وضع المجموعات)
log "Reloading PM2..."
pm2 reload "$APP_NAME" 2>&1 | tee -a "$LOG_FILE"
pm2 save 2>&1 | tee -a "$LOG_FILE"
 
# فحص الصحة مع إعادة المحاولة
log "Running health check..."
for i in $(seq 1 $MAX_RETRIES); do
    HTTP_CODE=$(curl -s -o /dev/null -w '%{http_code}' "$HEALTH_URL" 2>/dev/null || echo "000")
    if [ "$HTTP_CODE" = "200" ]; then
        log "Health check passed (HTTP $HTTP_CODE)"
        log "=== Deploy completed successfully ==="
        exit 0
    fi
    log "Health check attempt $i/$MAX_RETRIES (HTTP $HTTP_CODE). Retrying in ${RETRY_INTERVAL}s..."
    sleep $RETRY_INTERVAL
done
 
log "ERROR: Health check failed after $MAX_RETRIES attempts"
log "Rolling back to previous PM2 state..."
pm2 restart "$APP_NAME" 2>&1 | tee -a "$LOG_FILE"
exit 1

اجعله قابلا للتنفيذ:

bash
chmod +x deploy.sh

انشر من جهازك المحلي:

bash
ssh root@your-server-ip "bash /var/www/akousa.net/deploy.sh"

القرارات الرئيسية في هذا السكريبت:

set -euo pipefail: السكريبت يتوقف فورا عند أي خطأ. بدون هذا، npm install الفاشل يستمر بصمت إلى خطوة البناء، وتحصل على خطأ غامض يهدر 20 دقيقة لتصحيحه.

rm -rf .next قبل البناء: Next.js لديه ذاكرة مؤقتة للبناء تنتج أحيانا مخرجات قديمة. وقعت في هذا مرة — صفحة أظهرت محتوى قديما رغم تحديث الكود المصدري. حذف مجلد البناء يضيف ربما 15 ثانية للبناء لكنه يضمن مخرجات جديدة.

pm2 reload بدلا من pm2 restart: هذا هو جزء عدم التوقف. في وضع المجموعات، reload يقوم بإعادة تشغيل تدريجية — يرفع مثيلات جديدة بالكود المحدث، ينتظر حتى تكون جاهزة، ثم يوقف القديمة بلطف. في أي نقطة لا تكون صفر مثيلات تعمل.

فحص الصحة مع إعادة المحاولة: Next.js يستغرق بضع ثوان للإحماء بعد إعادة التشغيل. السكريبت ينتظر حتى 30 ثانية (10 محاولات × 3 ثوان)، يتحقق إذا كان التطبيق يستجيب بـ HTTP 200. إذا لم يفعل، شيء خاطئ وتحتاج أن تعرف فورا — ليس أن تكتشف من مستخدم.

التراجع عند الفشل: إذا فشل فحص الصحة بعد كل المحاولات، السكريبت يعيد تشغيل PM2 (الذي يحمل آخر حالة محفوظة). ليس تراجعا مثاليا، لكنه أفضل من ترك الخادم في حالة معطلة.

عندما تتعطل الأشياء في الساعة 2 صباحا#

إليك ما صححت أخطاءه فعلا على هذا الإعداد بالذات:

"الموقع معطل"#

أول الأوامر التي يجب تشغيلها:

bash
pm2 status
pm2 logs akousa --lines 50
sudo systemctl status nginx
sudo tail -50 /var/log/nginx/error.log

تسع مرات من عشر، pm2 logs يخبرك فورا بما حدث. متغير بيئة مفقود، أو اتصال قاعدة بيانات فاشل، أو رفض وعد غير معالج.

"الذاكرة تستمر في النمو"#

bash
pm2 monit

هذا يعطيك لوحة تحكم حية لوحدة المعالجة المركزية والذاكرة لكل عملية. إذا ارتفعت الذاكرة بثبات بدون أن تستقر، لديك تسرب. إعداد max_memory_restart في إعداد النظام البيئي هو شبكة أمانك — PM2 سيعيد تشغيل العملية قبل أن تسقط الخادم.

للتحقيق الأعمق:

bash
pm2 describe akousa

هذا يُظهر وقت التشغيل وعدد إعادات التشغيل ولقطات الذاكرة. إذا رأيت 47 إعادة تشغيل في آخر 24 ساعة، هذا دليلك.

"شهادة SSL انتهت صلاحيتها"#

bash
sudo certbot certificates

يسرد جميع الشهادات مع تواريخ انتهائها. إذا فشل التجديد التلقائي:

bash
sudo certbot renew --force-renewal
sudo systemctl reload nginx

"مساحة القرص ممتلئة"#

bash
df -h
du -sh /var/log/*
pm2 flush

pm2 flush يمسح جميع ملفات سجلات PM2 فورا. إذا لم تُعِدّ تدوير السجلات (أخبرتك)، هذا حيث تشعر بالألم.

الأمر الذي أشغله كل صباح#

bash
ssh deploy@akousa.net "pm2 status && df -h / && uptime"

ثلاثة أشياء في سطر واحد: هل عملياتي تعمل، هل قرصي بخير، هل الخادم محمّل. يستغرق ثانيتين. يكتشف المشاكل قبل المستخدمين.

ما لن تخبرك به معظم الأدلة#

خطوة البناء هي أكبر نقطة ضعف لديك. على VPS بـ 1 غيغابايت ذاكرة عشوائية، npm run build لتطبيق Next.js يمكن أن يستهلك 800 ميغابايت+ من الذاكرة. إذا كان PM2 يشغل تطبيقك في مثيلين أثناء البناء، ستنفد الذاكرة. الحلول: استخدم ملف swap (على الأقل 2 غيغابايت)، أو أوقف التطبيق أثناء البناء وتقبل بضع ثوان من التوقف. أستخدم swap.

bash
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

--legacy-peer-deps في أمر التثبيت هو رائحة كود، وليس حلا. أستخدمه لأن بعض الحزم في شجرة التبعيات لم تحدث نطاقات تبعيات النظراء. كل بضعة أشهر أحاول إزالته. يوما ما سيعمل. حتى ذلك الحين، أنشر.

اختبر سكريبت النشر من الصفر. انسخ مستودعك على خادم جديد وشغّل كل خطوة يدويا. عدد مشاكل "يعمل على جهازي" المختبئة في سكريبتات النشر محرج. وجدت ثلاث مشاكل في سكريبتي عندما فعلت هذا — حزم عامة مفقودة وصلاحيات ملفات خاطئة ومسار لم يكن موجودا إلا بسبب إعداد يدوي سابق.

ضع عنوان IP لخادمك في إعداد SSH. توقف عن كتابة عناوين IP:

bash
# ~/.ssh/config
Host akousa
    HostName 69.62.66.94
    User deploy
    IdentityFile ~/.ssh/id_ed25519

الآن ssh akousa هو كل ما تحتاجه. الأشياء الصغيرة تتراكم.

القائمة الكاملة#

قبل أن تقول أنك انتهيت:

  • مستخدم غير جذر مع صلاحية sudo
  • مصادقة مفتاح SSH فقط، مصادقة كلمة المرور معطلة
  • UFW مُفعّل مع المنافذ الضرورية فقط مفتوحة
  • Fail2Ban يحمي SSH
  • تحديثات الأمان التلقائية مُفعّلة
  • Node.js مثبت عبر NVM
  • PM2 يشغل تطبيقك في وضع المجموعات
  • سكريبت بدء تشغيل PM2 مُهيّأ (ينجو من إعادة التشغيل)
  • تدوير سجلات PM2 مثبت
  • وكيل عكسي Nginx بترويسات صحيحة
  • SSL عبر Let's Encrypt مع تجديد تلقائي
  • سكريبت نشر مع فحوصات صحة
  • ملف swap مُهيّأ (لهامش البناء)
  • مُختبر: أعد تشغيل الخادم وتحقق أن كل شيء يعود

هذا البند الأخير هو الذي يتخطاه الناس. لا تكن ذلك الشخص. أعد تشغيل الخادم، انتظر 60 ثانية، وتحقق إذا كان تطبيقك يعمل. إذا لم يكن كذلك، سكريبتات بدء التشغيل مُهيّأة بشكل خاطئ وستكتشف ذلك في أسوأ وقت ممكن.

هل هذا "بمستوى المؤسسات"؟#

لا. وهذا هو بيت القصيد.

هذا الإعداد يخدم هذه المدونة بشكل موثوق بأقل من 10 دولارات/شهر. يُنشر في 30 ثانية بأمر واحد. أفهم كل جزء منه. عندما ينكسر شيء، أعرف بالضبط أين أبحث.

هل يمكنني استخدام Docker؟ بالتأكيد. هل يمكنني استخدام Kubernetes؟ تقنيا. هل يمكنني إعداد خط أنابيب CI/CD كامل مع بيئات اختبار ونشر تدريجي؟ بالتأكيد.

لكنني تعلمت أن أفضل بنية تحتية هي التي تفهمها فعلا، ويمكنك تصحيح أخطائها في الساعة 2 صباحا، ولا تكلف أكثر مما يكسبه المشروع. لموقع شخصي أو MVP لمنتج SaaS أو شركة ناشئة صغيرة — هذا هو ذلك الإعداد.

انشر أولا. وسّع عندما تحتاج. ودائما، دائما، اختبر سكريبت النشر على خادم جديد.