Запуск Node.js-приложения командой node server.js подходит для теста, но в реальном проекте быстро приводит к проблемам. Любое необработанное исключение останавливает процесс целиком, обрыв SSH-сессии выключает приложение, а после перезагрузки сервера кто-то должен вручную запустить его снова. PM2 — менеджер процессов, который берёт эти задачи на себя. Он держит приложение в фоне, сразу перезапускает его после падения и пишет весь вывод в лог-файлы.
Установка PM2 и первый запуск
PM2 устанавливается через npm как глобальный пакет, поэтому на сервере уже должен быть Node.js. После установки приложение запускается одной командой, и ему стоит дать понятное имя, чтобы потом управлять им по имени.
npm install -g pm2
cd /var/www/misol-app
pm2 start server.js --name misol-app
pm2 list
Таблица pm2 list показывает статус каждого процесса, число перезапусков, загрузку процессора и объём памяти. Если число в колонке перезапусков быстро растёт, значит приложение падает сразу после старта и пора смотреть логи.
Ecosystem-файл: все настройки в одном месте
Каждый раз набирать в командной строке десяток параметров неудобно и чревато ошибками. Вместо этого PM2 предлагает ecosystem-файл. Он лежит в папке проекта, хранится в Git, и каждый участник команды запускает приложение с одинаковыми настройками. В примере ниже заданы порт, переменные окружения и лимит памяти.
// ecosystem.config.js
module.exports = {
apps: [{
name: "misol-app",
script: "server.js",
cwd: "/var/www/misol-app",
instances: 1,
max_memory_restart: "300M",
env: {
NODE_ENV: "production",
PORT: 3000
}
}]
};
pm2 start ecosystem.config.js
pm2 restart ecosystem.config.js --update-env
Параметр max_memory_restart автоматически перезапускает приложение, если оно превысило заданный объём памяти. Это спасает сервер от полного зависания при утечке памяти, но саму проблему не решает, поэтому причину всё равно нужно искать в коде. Флаг --update-env заставляет PM2 перечитать изменённые переменные окружения.
Работа с логами
Для каждого приложения PM2 ведёт два лога: обычный вывод и ошибки. По умолчанию они лежат в каталоге ~/.pm2/logs пользователя. Для наблюдения в реальном времени удобна команда pm2 logs, а последние несколько сотен строк выводятся с параметром --lines.
pm2 logs misol-app
pm2 logs misol-app --lines 200
pm2 flush misol-app
Со временем лог-файлы разрастаются и могут заполнить диск. Чтобы этого не случилось, стоит установить модуль ротации логов: он сжимает старые файлы и удаляет лишние сверх заданного количества.
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7
Cluster-режим: используем все ядра
Один процесс Node.js в основном использует одно ядро процессора. Если ядер несколько, cluster-режим PM2 запускает несколько копий приложения и распределяет входящие запросы между ними. Этот режим подходит только приложениям, которые не хранят состояние в памяти: сессии должны жить в Redis или базе, иначе пользователь будет попадать на другую копию и терять авторизацию.
pm2 start server.js --name misol-app -i max
pm2 reload misol-app
Команда reload обновляет копии по очереди, поэтому при выкладке нового кода сайт не пропадает ни на секунду. Обычный restart останавливает и запускает все копии одновременно.
Автозапуск после перезагрузки сервера
Сам PM2 тоже должен стартовать вместе с системой, иначе после перезагрузки не заработает ни одно приложение. Для этого нужно два шага: создать startup-скрипт и сохранить текущий список процессов.
pm2 startup
# скопируйте и выполните выведенную команду sudo env PATH=...
pm2 save
Добавив новое приложение или удалив старое, не забудьте снова выполнить pm2 save. Иначе после перезагрузки восстановится старый список. Проверить результат проще всего на деле: перезагрузите сервер в спокойное время и убедитесь через pm2 list, что все процессы поднялись сами.
Практический пример: сайт частной школы и API
Частная школа в Ташкенте на домене example.uz держит два Node.js-сервиса: API с оценками для родителей и небольшой воркер, рассылающий уведомления в Telegram. Оба описаны в одном ecosystem-файле: API работает в cluster-режиме в двух копиях, воркер — в одной. В день выхода четвертных оценок нагрузка растёт, и копии API делят её между собой, а лимит памяти защищает сервер даже при утечке. Для выкладки новой версии разработчик выполняет только git pull и pm2 reload ecosystem.config.js.
Связка с Nginx
PM2 запускает приложение, но открывать его в интернет напрямую не стоит — лучше поставить перед ним Nginx. Nginx принимает порты 80 и 443, подключает SSL-сертификат и передаёт запросы на внутренний порт 3000. Ниже минимальная настройка прокси.
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
Для такой настройки нужен сервер с root-доступом. Взяв VPS в кабинете sayt.uz и установив на него Node.js, PM2 и Nginx, вы сможете выполнить все описанные шаги с полным контролем.