
به اشتراک بگذارید

به اشتراک بگذارید
سرور دیشب برای بهروزرسانی کرنل ریبوت شده و صبح API شما جواب نمیدهد، با اینکه دیروز با pm2 بالا آمده بود. مدیر پروسس برنامه را فقط وقتی بعد از ریبوت برمیگرداند که سرویس خودکار ساخته و فهرست برنامهها ذخیره شده باشد، و مسیر Node.js که nvm نصب کرده هنوز سر جایش باشد.
| اشتباه | نشانه | فرمان درست |
|---|---|---|
| اجرا با nohup یا screen | بعد از ریبوت پروسسی نیست | فرمان pm2 startup |
| سرویس بدون ذخیره فهرست | فهرست برنامهها خالی یا قدیمی برمیگردد | فرمان pm2 save بعد از هر تغییر |
| ارتقای Node با nvm | برنامه بعد از ریبوت بالا نمیآید | فرمان pm2 unstartup و دوباره startup |
| حالت cluster با session در حافظه | کاربر مدام از حساب بیرون میافتد | نگهداری session در Redis |
| لاگ بدون چرخش | دیسک آرامآرام پر میشود | ماژول pm2-logrotate |
💡 دو فرمانی که اجرای دائمی را کامل میکنند
مدیر پروسس برنامه کرشکرده را خودش دوباره اجرا میکند؛ برگشتن بعد از ریبوت به سرویس startup و فهرست save نیاز دارد.
✅ بعد از اضافه یا حذف هر برنامه، فهرست را دوباره ذخیره کنید.
✅ خود مدیر پروسس هم با npm نصب میشود؛ اگر روی سرور داخلی نصب نشد، مقاله تحریم npm علتش را میگوید.
این اشتباهها معمولاً در بدترین لحظه پیدا میشوند: ریبوتی که خودتان برنامهریزی نکردهاید. بعد از هر رفع، در ساعت کاری یک بار sudo reboot بزنید تا همان لحظه را بیخطر بازسازی کنید؛ ریبوت یازده صبح با چای کنار دست، ارزانتر از ریبوت سه بامداد است.
📌 هفت کارت خرابی
◀️ نصب Node.js با nvm؛ اشتباهی که بعد از ریبوت پیدا میشود
◀️ سرویس را بعد از ریبوت زنده نگه دارید؛ startup و save
◀️ حالت cluster همیشه سریعتر نیست
◀️ چرخش لاگ و پروکسی WebSocket

مدیر نسخه nvm برای هر کاربر جدا نصب میشود و هر نسخه Node.js را در پوشهای زیر ~/.nvm/versions/node میگذارد؛ پکیجهای سراسری، از جمله pm2، کنار همان نسخه مینشینند. پس همه فرمانهای این مقاله را با همان کاربری بزنید که برنامه را اجرا میکند، نه root.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.8/install.sh | bash
source ~/.bashrc # nvm را در همین شل بارگذاری میکند
nvm install --lts
npm install pm2@latest -g
نشانه: در ترمینال همهچیز سالم است، اما بعد از ریبوت برنامه یا بالا نمیآید یا با نسخه قبلی Node اجرا میشود.
سرویس خودکار مسیر پوشه bin نسخهای را نگه میدارد که هنگام ساختنش فعال بوده؛ اگر نسخه قبلی را پاک کنید، به فایلی اشاره میکند که دیگر نیست. مستندات Startup Script برای همین حالت میگوید بعد از ارتقای Node پیکربندی قبلی را حذف کنید و سرویس تازه بسازید. قدمها: نصب نسخه جدید با پکیجهای سراسری، پیشفرض کردنش، جایگزینی نسخه در حافظه با update و ساختن دوباره سرویس.
nvm install --reinstall-packages-from=current 'lts/*'
nvm alias default node
pm2 update
pm2 unstartup # خروجی را کپی و اجرا کنید
pm2 startup # خروجی را کپی و اجرا کنید
نشانه: فرمان nvm install روی دریافت فایل میماند.
نشانی پیشفرض https://nodejs.org/dist است و متغیر NVM_NODEJS_ORG_MIRROR آن را عوض میکند؛ میرری را بگذارید که به آن اعتماد دارید.
export NVM_NODEJS_ORG_MIRROR=https://MIRROR.EXAMPLE/dist
nvm install --lts

فرمان startup در pm2 یک سرویس systemd میسازد که هنگام بوت، فهرست ذخیرهشده برنامهها را برمیگرداند و save همان فهرست را روی دیسک مینویسد. اگر یکی از این دو را جا بیندازید، ریبوت بعدی برنامه را خاموش رها میکند.
در پایانه اتوبوسرانی، مسئول حرکت اتوبوس خراب را با اتوبوس دیگری روی همان خط عوض میکند و در دفتر مینویسد؛ مدیر پروسس با برنامه کرشکرده همین کار را میکند. صبح هم فقط خطهای فهرست روی میز، یعنی dump.pm2، راه میافتند.
نشانه: برنامه تا اولین کرش یا ریبوت کار میکند و بعد کسی برش نمیگرداند.
pm2 start app.js --name api
pm2 startup # خط sudo چاپشده را کپی و اجرا کنید
pm2 save
مستندات میخواهد startup را بدون sudo بزنید؛ خروجیاش خطی با sudo است که مسیر Node، نام کاربر (-u) و پوشه خانه (--hp) را دارد.
🔸 فرمان startup چه چیزی روی دیسک مینویسد
روی سیستمهای systemd فایل /etc/systemd/system/pm2-USER.service ساخته و فعال میشود. در قالب کد منبع پروژه، خط Environment=PATH پوشه bin همان نسخه Node را نگه میدارد و ExecStart فرمان resurrect را اجرا میکند. نسخه سرور خودتان را با systemctl cat pm2-$USER ببینید.
نشانه: بعد از ریبوت فقط برنامههای قدیمی برمیگردند یا برنامه حذفشده دوباره ظاهر میشود.
دستور save فهرست فعلی را در ~/.pm2/dump.pm2 مینویسد و resurrect هنگام بوت همین فایل را میخواند؛ هر start یا delete بعد از آخرین save، با ریبوت گم میشود. آزمون نهایی:
sudo reboot
# بعد از اتصال دوباره
pm2 list
journalctl -u pm2-$USER
حالت cluster در pm2 چند نسخه از برنامه را با ماژول cluster خود Node.js روی هستههای پردازنده پخش میکند تا همه روی یک پورت گوش بدهند. روی سرور تکهستهای یا برنامهای با session در حافظه، دردسرش از سرعتش بیشتر است.
این خط cluster را روشن میکند، اما تنظیماتش جایی ثبت نمیشود. اگر api از کارت ۳ هنوز اجراست، با پیام Script already launched متوقف میشود:
pm2 start app.js --name api -i max --max-memory-restart 300M
همان تنظیم در ecosystem.config.js؛ برنامه پورت را از process.env.PORT میخواند:
module.exports = {
apps: [{
name: "api",
script: "./app.js",
instances: "max",
exec_mode: "cluster",
max_memory_restart: "300M",
env: {
PORT: 3000
},
env_production: {
NODE_ENV: "production",
PORT: 3000
}
}]
}
برنامهای که با همین نام در حالت fork اجراست، با start از فایل به cluster تبدیل نمیشود و بیصدا ریاستارت میخورد. حذفش کنید، از فایل اجرا کنید و فهرست را دوباره ذخیره کنید:
pm2 delete api
pm2 start ecosystem.config.js --env production
pm2 save
pm2 list # ستون mode باید cluster باشد
🔸 فایل ecosystem یا فلگهای خط فرمان
مستندات فایل پیکربندی شرط میگذارد که نام فایل به .config.js ختم شود تا مدیر پروسس آن را فایل تنظیمات بشناسد. مقادیر env بر متغیرهای شل غلبه دارند و --env production سراغ env_production میرود.
نشانه: بعد از روشن کردن cluster، کاربر هر چند درخواست یک بار از حساب بیرون میافتد، چون درخواست بعدی به پروسسی میرسد که او را نمیشناسد.
مقدار max یک پروسس برای هر هسته میسازد؛ روی سرور یک vCPU یعنی همان یک پروسس. پخش بار بین چند سرور در مقاله لود بالانسر چیست آمده است.
⚠️ session در حافظه با cluster کنار نمیآید
مستندات حالت cluster میگوید برنامه باید stateless باشد. session و اتصال WebSocket در حافظه یک پروسس بین نسخهها مشترک نیست؛ آن را در Redis یا دیتابیس نگه دارید، یا با یک instance اجرا کنید.
فرمان restart پروسس را میکشد و دوباره اجرا میکند، ولی reload در حالت cluster بدون قطعی انجام میشود. هنگام توقف، اول SIGINT میرسد و اگر برنامه ظرف ۱.۶ ثانیه بسته نشود، SIGKILL میگیرد؛ برای بستن آرام اتصال دیتابیس، این مهلت را با kill_timeout بالا ببرید.
pm2 reload ecosystem.config.js --only api

خروجی برنامه در پوشه ~/.pm2/logs جمع میشود و طبق مستندات، چرخاندن و محدود کردن فضای آن کار ماژولی جداگانه است. Nginx هم با تنظیم پیشفرض، هدرهای WebSocket را به برنامه نمیرساند.
نشانه: فرمان df -h دیسک را نزدیک به پر نشان میدهد و بزرگترین فایلها لاگهای برنامهاند.
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:compress true
pm2 conf
در README ماژول، پیشفرضها چرخش در حجم 10M، نگهداری ۳۰ فایل (retain) و چرخش اجباری هر نیمهشب است و فشردهسازی خاموش است. ماژول از مخزن npm دانلود میشود؛ اگر نصبش خطا داد، همان تنظیم registry مقاله تحریم npm اینجا هم کار میکند.
نشانه: صفحه باز میشود، اما WebSocket وصل نمیشود یا بعد از ۶۰ ثانیه سکوت قطع میشود.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 240s;
}
}
طبق مستندات ماژول proxy در nginx، پیشفرض proxy_http_version تا پیش از نسخه 1.29.7 برابر 1.0 بود و از این نسخه 1.1 است؛ نسخه مخزن توزیع ممکن است قدیمیتر باشد، پس خط را صریح بنویسید. پیشفرض proxy_read_timeout ۶۰ ثانیه است.
متن را در فایلی .conf بگذارید که nginx.conf آن را include میکند؛ nginx -T پیکربندی بارشده را نشان میدهد. برای HTTPS، listen 443 ssl و مسیر گواهی را اضافه کنید.
sudo nginx -t && sudo nginx -s reload
سرور Node.js بدون host روی همه نشانیها گوش میدهد؛ با app.listen(process.env.PORT, '127.0.0.1') درخواست فقط از Nginx میرسد.
مدیر پروسس را یک بار راه انداختهاید و ته دلتان مطمئن نیستید بعد از ریبوت برگردد؟ این سوالها شب قبل از ریبوت به ذهن میرسند.
فقط وقتی سرویس خودکار ساخته شده و فهرست بعد از آخرین تغییر ذخیره شده باشد؛ یک ریبوت دستی جواب قطعی میدهد.
بدون sudo. خروجی آن خطی با sudo است که مسیر Node و نام کاربر شما را دارد؛ همان را اجرا کنید.
نسخه جدید را پیشفرض کنید، update بزنید، پیکربندی قبلی را با unstartup حذف کنید و سرویس را دوباره بسازید.
در ~/.pm2/logs. در حالت fork نام فایل api-out.log است و در حالت cluster شماره پروسس هم میآید: api-out-0.log، api-out-1.log. دستور pm2 logs api --lines 200 همه را یکجا نشان میدهد.
خیر. این حالت برای سرورهای شبکهای است و برنامه باید stateless باشد؛ اسکریپت غیر JavaScript از نسخه 7.1.0 با هشدار به fork برمیگردد.
فرمان unstartup دستور حذف سرویس را چاپ میکند؛ آن را اجرا کنید. فایل dump روی دیسک میماند.
اجباری نیست، اما راهنمای Nginx در مستندات رسمی همین مدیر پروسس این چیدمان را پیشنهاد میکند: Nginx فایل ثابت و SSL را مدیریت و ترافیک را به برنامه منتقل میکند.
جمعبندی؛ ریبوت را قبل از سرور خودتان امتحان کنید اجرای دائمی با pm2 روی دو فرمان بنا شده است: startup که سرویس systemd را میسازد و save که فهرست برنامهها را روی دیسک مینویسد. بیشتر خرابیهای بعد از ریبوت به همین دو برمیگردد، یا به مسیری از nvm که دیگر وجود ندارد. بعد از هر ارتقای Node سرویس را دوباره بسازید، cluster را فقط برای برنامه stateless روشن کنید و چرخش لاگ و هدرهای Upgrade را پیش از ترافیک واقعی تنظیم کنید. بعد یک ریبوت دستی بزنید و فهرست پروسسها را ببینید.
🚀 وقتی npm install روی سرور داخلی گیر میکند
سروری که به registry npm نرسد، نه ماژول لاگ را نصب میکند نه نسخه تازه مدیر پروسس را؛ میرور جایگزین در راهنمای زیر آمده است.
برنامه Node شما با کدام روش زنده میماند و تا حالا بعد از ریبوتی برنگشته؟ تعریفش کنید؛ شاید کارت هشتم باشد.
منابع