Запустить Node.js на VPS — задача на 30–40 минут, если делать всё в правильном порядке. В этом руководстве разберём деплой Node.js-приложения на сервер с Ubuntu 24.04 LTS от и до: установка Node.js через NodeSource или nvm, запуск процесса под управлением PM2 с автостартом после перезагрузки, настройка Nginx как reverse proxy и подключение HTTPS. Все команды рабочие — можно копировать в терминал. На выходе получите продакшен-схему, которой пользуются и одиночные разработчики, и небольшие команды: Node-процесс слушает локальный порт, Nginx принимает трафик из интернета, PM2 следит, чтобы приложение не падало.
Что понадобится
- VPS с Ubuntu 24.04 LTS и root-доступом. Для API или SSR-приложения на Next.js/Nuxt хватит тарифа Start у Cheap-Host — 450 ₽/мес за 6 vCPU, 8 ГБ RAM и 96 ГБ NVMe. NVMe заметно ускоряет
npm ciи сборку фронтенда. - Домен, направленный на IP сервера (для HTTPS — обязательно).
- SSH-доступ — если подключаетесь впервые, смотрите инструкцию как подключиться к VPS по SSH.
- Приложение в git-репозитории — в примерах используем условный API на Express, слушающий порт 3000.
Шаг 1. Подготовка сервера
Обновите пакеты и откройте нужные порты. Наружу должны смотреть только SSH, HTTP и HTTPS — порт самого приложения (3000) закрыт файрволом:
sudo apt update && sudo apt upgrade -y
sudo apt install -y git curl ufw
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Подробнее о правилах файрвола — в статье про настройку UFW на Ubuntu.
Шаг 2. Установка Node.js: NodeSource или nvm
В репозиториях Ubuntu версия Node.js обычно отстаёт, поэтому используют один из двух способов.
Вариант А: NodeSource (рекомендуется для продакшена)
Node.js ставится системно, обновляется вместе с apt upgrade, одинаково доступен всем пользователям и systemd-службам:
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node -v
npm -v
Вариант Б: nvm (несколько версий Node.js на одном сервере)
Менеджер версий nvm ставит Node.js в домашний каталог пользователя. Удобно, когда на сервере живут проекты с разными версиями:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
source ~/.bashrc
nvm install --lts
node -v
Важно: при nvm-установке PM2 и Node.js принадлежат конкретному пользователю — команду автозапуска pm2 startup нужно выполнять от него же, а не от root.
Шаг 3. Деплой кода и зависимости
Разместим приложение в /var/www:
sudo mkdir -p /var/www && sudo chown $USER:$USER /var/www
cd /var/www
git clone https://github.com/youruser/yourapp.git app
cd app
npm ci --omit=dev
cp .env.example .env
nano .env
npm ci вместо npm install ставит зависимости строго по package-lock.json — сборка воспроизводима, а на NVMe-диске это занимает секунды. Секреты (порт, строка подключения к базе, API-ключи) держите в .env, а не в коде. Если проект собирается (TypeScript, Next.js), выполните npm run build.
Шаг 4. PM2: запуск, логи и автозапуск
PM2 — менеджер процессов для Node.js: перезапускает упавшее приложение, пишет логи, умеет cluster-режим и нулевой простой при обновлении.
sudo npm install -g pm2
cd /var/www/app
pm2 start app.js --name myapp
pm2 status
Для приложения с npm-скриптом запуска: pm2 start npm --name myapp -- start. Если API упирается в CPU, включите cluster-режим — по процессу на каждое ядро:
pm2 start app.js --name myapp -i max
Теперь автозапуск после перезагрузки сервера — два обязательных шага, которые чаще всего забывают:
pm2 startup systemd
# выполните команду, которую выведет pm2 startup
pm2 save
pm2 startup создаёт systemd-юнит, а pm2 save фиксирует текущий список процессов — без него после ребута PM2 стартует пустым. Полезные команды на каждый день:
pm2 logs myapp— логи в реальном времени;pm2 monit— CPU и память по процессам;pm2 reload myapp— перезапуск без простоя (в cluster-режиме);pm2 restart myapp— обычный перезапуск.
Шаг 5. Nginx как reverse proxy
Nginx принимает запросы на 80/443 и проксирует их в Node-процесс на 127.0.0.1:3000. Установка и конфиг:
sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/myapp
Содержимое файла:
server {
listen 80;
server_name example.com www.example.com;
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;
}
}
Заголовки Upgrade и Connection нужны для WebSocket (Socket.IO и т.п.). Активируйте конфиг и проверьте синтаксис:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Откройте http://ваш-IP — должно отвечать приложение. У Cheap-Host каждый VPS получает выделенный IPv4, так что проверить можно ещё до привязки домена.
Шаг 6. Домен и HTTPS
Создайте A-запись домена, указывающую на IP сервера (пошагово — в статье как привязать домен к VPS), затем выпустите бесплатный сертификат:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
Certbot сам поправит конфиг Nginx и настроит автопродление. Детали и проверка автопродления — в руководстве по Let's Encrypt.
Типичные ошибки при деплое Node.js
- Приложение слушает 0.0.0.0 с открытым портом. Node-процесс должен слушать 127.0.0.1, а наружу смотрит только Nginx.
- Забыли
pm2 save. После перезагрузки сервера приложение не поднялось — классика.pm2 startup+pm2 saveвсегда идут парой. - 502 Bad Gateway. Nginx жив, а Node-процесс — нет. Смотрите
pm2 logs: чаще всего не хватает переменной в.envили порт в конфиге не совпадает с портом приложения. - Сборка падает по памяти. На серверах с 1–2 ГБ RAM
npm run buildможет убиваться OOM-киллером. Помогает swap или тариф с запасом RAM — у Start от Cheap-Host 8 ГБ, чего хватает и на сборку Next.js. - Деплой под root. Заведите отдельного пользователя с sudo и запускайте PM2 от него.
FAQ
Можно ли обойтись без Nginx и открыть порт приложения наружу?
Технически да, но не стоит. Nginx отдаёт статику быстрее Node.js, терминирует TLS, ограничивает размер запросов и позволяет разместить несколько приложений на одном сервере. Node-процесс при этом слушает только 127.0.0.1 и не торчит в интернет.
Что выбрать для продакшена: NodeSource или nvm?
Для сервера с одним приложением удобнее NodeSource: Node.js ставится системно и обновляется через apt. nvm полезен, когда на сервере несколько проектов с разными версиями Node.js.
Сколько ресурсов нужно Node.js-приложению на VPS?
Типичный API на Express/Fastify занимает 80–200 МБ RAM на процесс. Пет-проекту хватит 1–2 ГБ, для продакшена с cluster-режимом считайте по процессу на ядро плюс запас на сборки. Тариф Start (6 vCPU, 8 ГБ RAM) закрывает большинство сценариев.
Когда нужен cluster-режим PM2?
Node.js однопоточный: один процесс грузит одно ядро. Если приложение упирается в CPU, запустите pm2 start app.js -i max — PM2 поднимет по процессу на ядро и распределит запросы между ними без изменения кода.
Как обновлять приложение без простоя?
git pull, npm ci, при необходимости npm run build, затем pm2 reload myapp вместо restart — в cluster-режиме процессы перезапустятся по очереди, и сервис продолжит отвечать.
Вывод
Схема «Node.js + PM2 + Nginx» — проверенный минимум для продакшена: PM2 держит процесс живым и стартует его после ребута, Nginx закрывает TLS, статику и WebSocket, а приложение остаётся за файрволом. Освоив её, логичный следующий шаг — упаковать сервис в контейнер: смотрите Docker на VPS. Если для деплоя нужен сервер — у Cheap-Host тариф Start от 450 ₽/мес: 6 vCPU, 8 ГБ RAM, NVMe, KVM с полным root, безлимитный трафик и выдача сервера за 45–60 секунд. Выбрать конфигурацию можно на cheap-host.onl.