+7 (920) 556-26-91 пн–пт: 10:00–19:00 (МСК)
Проконсультироваться

Инструкции

Как установить Node.js на VPS (Ubuntu 24.04) через mise

LTS 24 через mise use -g node@lts, без apt 18 и без NodeSource. Проверка версии и systemd с абсолютным путём.

Как установить Node.js на VPS (Ubuntu 24.04) через mise

Короткий ответ: на VPS с Ubuntu 24.04 Node.js ставится через mise командой mise use -g node@lts — это LTS 24, на момент гайда latest v24.21.0, около 10 минут вместе с установкой самого mise. Не используйте apt install nodejs (там 18.19.1 EOL) и не подключайте NodeSource: при mise он не нужен.

Что понадобится

  • Ubuntu 24.04 LTS (noble), пользователь sudo, вход по ключу — см. первую настройку VPS;
  • mise с activate в bashrc — см. установку mise; если mise ещё нет, ниже есть минимальный блок;
  • открытые исходящие HTTPS; входящие 3000 в UFW не открывать;
  • 10 минут.

Документация Node.js: nodejs.org. Документация mise: mise.jdx.dev. К концу статьи у вас будет LTS 24 в пользовательском каталоге, проверка node -v / npm -v, крошечный HTTP-сервер на 127.0.0.1:3000 и systemd-юнит, который переживает reboot. Наружу порт 3000 не торчит — это сознательно.

Команды копируйте целиком. Если проверка шага не совпала с ожиданием — остановитесь. Типичная развилка: вы всё ещё в той SSH-сессии, где не было activate, и смотрите на /usr/bin/node вместо mise.

Почему не apt и не NodeSource

В репозиториях Ubuntu 24.04 пакет nodejs — это 18.19.1. К сентябрю 2026 это EOL: без нормальных обновлений безопасности и без современных API. Многие HOWTO до сих пор предлагают NodeSource — сторонний репозиторий, который борется с apt за один и тот же /usr/bin/node. На сервере с mise это лишняя точка поломки: apt обновляет «системный» node, mise держит свой, systemd берёт третий путь.

Способ Что получите на 24.04 Ставить?
apt install nodejs 18.19.1 EOL нет
NodeSource свой репозиторий в /usr нет, если есть mise
nvm Node в $HOME, конфликт PATH с mise нет
mise use -g node@lts LTS 24, v24.21.0 да

Если node уже стоит из apt, сначала проверьте:

command -v node
node -v
dpkg -l nodejs npm 2>/dev/null | grep ^ii

Если видите v18.19.1 и /usr/bin/node — не маскируйте это nvm. Снимите пакет после того, как убедитесь, что скрипты системы его не вызывают, либо просто не кладите /usr/bin впереди shims: mise activate должен стоять в bashrc, новая сессия, type node показывает shim.

Шаг 1. mise, если его ещё нет

Если mise —version уже отвечает v2026.9.6 — переходите к шагу 2. Если нет:

curl -fsSL https://mise.run | sh
echo 'eval "$(~/.local/bin/mise activate bash)"' >> ~/.bashrc

Закройте SSH и зайдите снова. PPA mise на Ubuntu 24.04 не подключайте (он для 26.04+). Проверка:

mise --version
mise doctor

Шаг 2. Ставим Node.js LTS

mise use -g node@lts
node -v
npm -v
command -v node
mise which node

Ожидание node -v: v24.21.0 (LTS-линия 24). npm -v должен напечатать номер встроенного npm — отдельно apt-пакет npm не ставьте. command -v node — shim в ~/.local/share/mise/shims/node. mise which node — реальный файл в ~/.local/share/mise/installs/node/24.21.0/bin/node. Для systemd нужен второй путь, не первый.

Именно mise use -g, не только mise install. install качает, use ещё и фиксирует глобальную версию. Без use в новом терминале снова «command not found» или старый /usr/bin/node.

Проверка, что это не apt:

node -p "process.version + ' ' + process.execPath"

execPath должен жить в ~/.local/share/mise/installs/…, не в /usr/bin/node. Если напечаталось v18.19.1 — вы смотрите системный пакет: либо не открыли новую сессию после activate, либо в bashrc ниже сидит nvm, либо mise use не выполняли.

Идентификатор node@lts всегда указывает на текущий LTS. На 13–14 сентября 2026 это линия 24 и конкретный latest v24.21.0. Когда выйдет следующий патч той же линии, повторный mise use -g node@lts подтянет его. Если нужно заморозить именно 24.21.0 в проекте, в каталоге приложения выполните mise use node@24.21.0 — появится локальный .tool-versions или mise.toml, и чужой LTS-апдейт этот каталог не заденет.

Глобальный npm i -g на сервере не используйте как способ доставить приложение. Пакеты проекта ставьте в его каталог (npm ci / npm install рядом с package.json). Глобальные кли (pnpm, например) — через mise, не через npm -g под sudo: sudo уходит в /usr/local и снова расходится с User= в systemd.

pnpm: не corepack, а mise

В Node.js 24 corepack ещё есть, но помечен как experimental. В Node.js 25 его убрали. Ставить pnpm через corepack enable на LTS 24 — привычка, которая сломается при следующем major. Канон этой серии: pnpm тоже через mise.

mise use -g pnpm
pnpm -v
mise which pnpm

Не фиксируйте в статье и в юнитах «магический» npm i -g pnpm под sudo: глобальный npm -g пишет не туда, куда вы думаете, и снова расходится с systemd. yarn/pnpm как плагины mise переживают смену каталога и смену версии Node.

Шаг 3. Hello на localhost

Проверьте, что рантайм реально запускает процесс, до того как писать юнит.

mkdir -p ~/hello-node
cat > ~/hello-node/server.js <<'EOF'
const http = require('http');
http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
  res.end('ok\n');
}).listen(3000, '127.0.0.1');
console.log('listen 127.0.0.1:3000');
EOF
node ~/hello-node/server.js

Во втором окне:

curl -sS http://127.0.0.1:3000/

Ответ — ok. С вашей домашней машины curl http://IP:3000 должен не открываться: порт в UFW закрыт, процесс слушает 127.0.0.1. Это правильно. Наружу hello выведет nginx (см. гайд по Certbot), не сам Node.

Остановите процесс Ctrl+C. Если «listen EADDRINUSE» — кто-то уже занял 3000: ss -tlnp | grep 3000. Не меняйте listen на 0.0.0.0 «чтобы проверить с ноутбука»: для проверки есть ssh -L 3000:127.0.0.1:3000 deploy@IP и curl уже с вашей машины на localhost. Так вы не учитесь открывать прикладной порт в UFW.

package.json для этого hello не обязателен. Когда появится настоящий сервис, держите его в отдельном каталоге, с собственным package-lock.json, и запускайте node того же mise, что в юните. Не ставьте второй Node «для этого проекта» через NodeSource — локальную версию фиксирует mise use без -g.

Шаг 4. systemd с абсолютным путём

Скопируйте вывод mise which node целиком. Подставьте своего пользователя и путь. Не вставляйте shim.

mise which node
# пример: /home/deploy/.local/share/mise/installs/node/24.21.0/bin/node

Юнит (пути замените на свои):

sudo tee /etc/systemd/system/hello-node.service <<'EOF'
[Unit]
Description=hello-node
After=network.target

[Service]
Type=simple
User=deploy
WorkingDirectory=/home/deploy/hello-node
ExecStart=/home/deploy/.local/share/mise/installs/node/24.21.0/bin/node /home/deploy/hello-node/server.js
Restart=on-failure
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now hello-node
sudo systemctl status hello-node --no-pager
curl -sS http://127.0.0.1:3000/

User= обязан совпасть с владельцем каталога installs. Если mise ставили под deploy, а в юните User=root (или наоборот) — ExecStart не найдёт файл. После enable —now status должен быть active, curl — снова ok. Логи: journalctl -u hello-node -e.

Когда смените patch-версию Node, путь 24.21.0 в ExecStart устареет. Снова mise which node, правка юнита, daemon-reload, restart. Не пытайтесь обойти это через shims: в systemd их нет. Не ставьте в юнит ExecStart=/bin/bash -lc ‘node server.js’: login-shell тянет bashrc, который в сервисах то читается, то нет, и маскирует кривой PATH.

Проверка автозапуска: systemctl is-enabled hello-node должен сказать enabled. После reboot (когда будете готовы) снова curl на 127.0.0.1:3000. Если сервис не поднялся — journalctl -u hello-node -b за текущую загрузку. Частые причины: опечатка в абсолютном пути, User= не тот, WorkingDirectory не существует, файл server.js не у того владельца.

UFW по-прежнему с 22/80/443. Когда появится домен, nginx будет проксировать на 127.0.0.1:3000, сертификат — по гайду Certbot. Сам Node до этого момента наружу не высовывается.

Проверка результата

node -v
npm -v
mise current
mise which node
systemctl is-active hello-node
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/

Ожидание: v24.21.0, current содержит node, is-active = active, HTTP 200. Если node -v другой — смотрите type node и nvm/apt в PATH.

Частые ошибки

  • apt install nodejs. Получите 18.19.1 EOL. Удалите пакет, поставьте node@lts через mise, проверьте execPath.
  • NodeSource «как во всех статьях». При mise не нужен. Два node в /usr и в ~/.local — классический «на сервере одна версия, в systemd другая».
  • ExecStart=/usr/bin/node или shim. Только вывод mise which. Shim без activate в юните не работает.
  • corepack enable и надежда на pnpm. На 24 experimental, с 25 убран. pnpm ставьте через mise.
  • UFW allow 3000. Не открывайте. Node слушает localhost, снаружи — nginx на 80/443.
  • Две копии node в PATH. type -a node покажет все. Первой должна быть shim mise. Если первой /usr/bin/node — снимите apt-пакет или почините порядок bashrc, новая сессия.
  • npm установлен из apt отдельно от node. Пара node 24 из mise + npm из Ubuntu даёт непредсказуемые префиксы. Нужен только npm, который пришёл с node@lts.

FAQ

Почему нельзя поставить Node из apt на Ubuntu 24.04?

Пакет nodejs там 18.19.1, линия уже EOL. Для нового сервиса это неподдерживаемый рантайм. Нужен LTS 24 через mise use -g node@lts, сейчас это v24.21.0.

Нужен ли NodeSource, если есть mise?

Нет. NodeSource ставит node в систему и конфликтует с shims. Один менеджер версий — mise, один бинарь для systemd — путь из mise which.

Как поставить pnpm и не сломать это на Node 25?

Не через corepack: на Node 24 он experimental, в 25 его нет. Команда mise use -g pnpm ставит pnpm отдельно от версии Node.

Как позже обновить LTS, не переписывая гайд с нуля?

Снова mise use -g node@lts, проверка node -v, затем обновить ExecStart свежим mise which node и systemctl restart. Глобальный npm i -g для сервиса не используйте.

Почему юнит не видит node, хотя в SSH node -v работает?

У systemd нет вашего bashrc и activate. В ExecStart нужен абсолютный путь из mise which, User= — тот же человек, у которого ставили mise. Проверьте journalctl -u hello-node.

Ещё гайды