Развертывание приложения Node.js (Express)

Чтобы разместить приложение Node.js на Lizard (lizard.build), разверните папку с package.json. По lock-файлу lizardpack выбирает менеджер пакетов, ставит зависимости, запускает скрипт build, если он есть, и стартует приложение скриптом start на порту 3000. Используется Node.js 22, если .nvmrc или engines.node не задают другую мажорную версию. Lizard передаёт порт в PORT; слушайте этот порт.

Статус тестов: пример на Express ниже запускался локально с Express 5.3.0, а маршрут к базе данных проверили с pg 8.23.1 и PostgreSQL 14. План сборки мы проверили в планировщике сборки lizardpack, который использует Lizard. Полный деплой по этому руководству мы ещё не проводили.

Перед началом

  • Node.js и npm на вашем компьютере, чтобы создать lock-файл и проверить приложение локально.
  • Lizard CLI с выполненным lizard login и тариф Pro или 7-дневный пробный период Pro (нужна карта). См. цены.

Для приложений на Next.js, Nuxt, Astro, SvelteKit и Vite есть отдельные руководства: см. руководства по фреймворкам.

Минимальное приложение на Express

package.json:

{
  "name": "express-app",
  "private": true,
  "type": "module",
  "scripts": {
    "start": "node server.js"
  },
  "engines": {
    "node": "22.x"
  },
  "dependencies": {
    "express": "^5.1.0"
  }
}

server.js:

import express from "express";
 
const app = express();
const port = Number(process.env.PORT) || 3000;
 
app.get("/", (req, res) => {
  res.send("Hello from Express on Lizard");
});
 
app.get("/healthz", (req, res) => {
  res.json({ status: "ok" });
});
 
app.listen(port, "0.0.0.0", () => {
  console.log(`listening on ${port}`);
});

Выполните npm install, чтобы создать package-lock.json, закоммитьте оба файла и добавьте node_modules и .env в .gitignore. Проверьте локально:

npm start
curl http://localhost:3000/healthz

Что lizardpack делает с приложением Node.js

ШагЧто происходит
Менеджер пакетовbun.lock или bun.lockb: Bun. pnpm-lock.yaml: pnpm. yarn.lock: Yarn. package-lock.json: npm ci. Нет lock-файла: npm install.
Версия Node.js.nvmrc, затем .node-version, затем .tool-versions, затем engines.node. Только мажорная версия, на образе node:<major>-slim. По умолчанию 22.
СборкаСкрипт build, если он есть в package.json, на отдельном этапе, где установлены ваши devDependencies
ЗапускСкрипт start; иначе node <main>; иначе первый из server.js, index.js, app.js, main.js, dist/index.js
РантаймNODE_ENV=production, порт 3000

Без скрипта build образ задаёт NODE_ENV=production до установки пакетов, поэтому devDependencies не ставятся. Тогда скрипт start, который вызывает nodemon, tsx или ts-node из devDependencies, падает. Для TypeScript компилируйте код в build и запускайте результат:

{
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

Файлы версий и их особые случаи описаны на странице версии рантайма. Оставьте команды сборки и запуска сервиса пустыми: если задана любая из них, Lizard пишет собственный Dockerfile на node:22-alpine и игнорирует ваши файлы версий. См. конвейер сборки.

Развертывание

Из корня приложения:

lizard init --name node-app
lizard add --service web
lizard up --service web --port 3000

lizard up загружает папку, собирает её на Lizard и выводит URL. Внутри git-репозитория он пропускает всё, что перечислено в .gitignore; вне git пропускает node_modules, но загружает файлы .env. См. развертывание из локального кода.

Для git push to deploy отправьте репозиторий на GitHub и подключите его командой lizard add -r your-org/your-app -n web. См. развертывание из GitHub.

Задайте переменные

lizard secrets set SESSION_SECRET="$(openssl rand -hex 32)" --service web

Читайте значения через process.env.SESSION_SECRET. Изменение переменной перезапускает сервис без пересборки. См. переменные и секреты.

Подключите Managed Postgres

lizard add postgres
lizard secrets set DATABASE_URL='${{postgres.DATABASE_PRIVATE_URL}}' --service web
npm install pg

Одинарные кавычки не дают оболочке обработать ${{…}}; при деплое Lizard подставляет вместо ссылки адрес базы данных в приватной сети проекта. Добавьте пул и маршрут в server.js:

import pg from "pg";
 
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
 
app.get("/db", async (req, res) => {
  const { rows } = await pool.query("SELECT now() AS now");
  res.json(rows[0]);
});

Express 5 передаёт отклонённый промис из маршрута своему обработчику ошибок, поэтому неудачный запрос возвращает HTTP 500, а не роняет процесс. Миграции запускайте со своего компьютера через публичный URL базы данных:

lizard run --service postgres -- npm run migrate

Для кеша или очереди задач так же добавьте Managed Redis: lizard add redis, затем REDIS_URL='${{redis.REDIS_PRIVATE_URL}}'.

Проверьте, что всё работает

lizard logs --build --service web
lizard logs --service web --tail 100
lizard ps

В логах рантайма появится listening on 3000. Запросите /healthz и /db по URL, который вывел lizard up.

Частые проблемы

СимптомЧто делать
npm ci падает, потому что lock-файл не совпадает с package.jsonВыполните npm install локально и закоммитьте package-lock.json.
nodemon: not found или tsx: not foundЭти инструменты лежат в devDependencies и для запуска не ставятся. Добавьте шаг build или перенесите инструмент в dependencies.
Деплой так и не становится работоспособнымСлушайте process.env.PORT. Жёстко заданный порт, например 5000, не совпадает с портом сервиса. См. сервис так и не становится работоспособным.
Не та версия Node.jsУкажите мажорную версию в .nvmrc, например 24, и разверните снова.
Cannot use import statement outside a moduleДобавьте "type": "module" в package.json или используйте require.

Процесс Node.js, который не отдаёт HTTP, например потребитель очереди или Discord-бот, работает как фоновый обработчик.

См. также

Обновлено