Пошук уроків, статей та іншого контенту
Сплануйте розгортання, керування версіями, секретами та змінними середовища на цільовій production-інфраструктурі.
Розгортання Node.js-застосунку — це не лише копіювання файлів на сервер. Потрібно заздалегідь визначити:
яку версію Node.js використовує production;
як встановлюються залежності;
які команди запускають і зупиняють застосунок;
де зберігаються секрети;
які змінні середовища потрібні застосунку;
як застосунок отримує порт і приймає зовнішні з’єднання;
як перевірити, що нова версія працює коректно.
Мета — зробити розгортання повторюваним: одна й та сама послідовність дій повинна давати передбачуваний результат на будь-якому production-середовищі.
Застосунок зазвичай має щонайменше такі середовища:
development — локальна розробка;
test або staging — перевірка змін перед production;
production — реальні користувачі та дані.
Для різних середовищ можуть відрізнятися:
адреса бази даних;
ключі сторонніх сервісів;
рівень журналювання;
дозволені джерела запитів;
порт;
параметри кешування.
Код бажано залишати однаковим, а відмінності передавати через змінні середовища.
Не варто вбудовувати production-значення безпосередньо в JavaScript:
const databaseUrl = "postgres://admin:password@example.com/app";Такий код ускладнює розгортання і може призвести до витоку облікових даних.
Натомість застосунок читає конфігурацію під час запуску:
const databaseUrl = process.env.DATABASE_URL;Версія Node.js повинна бути зафіксована і локально, і на production. Це зменшує ризик, що застосунок працюватиме на одному сервері, але зламається на іншому.
Основні способи зафіксувати версію:
поле engines у package.json;
файл .nvmrc для менеджера версій Node.js;
версія базового образу в Dockerfile, якщо застосунок запускається в контейнері.
Приклад package.json:
{
"name": "production-app",
"version": "1.0.0",
"private": true,
"type": "module",
"engines": {
"node": ">=20.11.0 <21"
},
"scripts": {
"start": "node src/server.js",
"check": "node --check src/server.js"
}
}Такий діапазон означає, що застосунок очікує Node.js версії 20, починаючи з 20.11.0, але не версії 21.
Файл .nvmrc може містити лише номер версії:
20.11.1Важливо розрізняти:
діапазон у engines описує підтримувані версії;
.nvmrc або версія образу задає конкретну версію для локального запуску;
lock-файл фіксує версії залежностей, але не версію Node.js.
Файл package-lock.json потрібно зберігати в системі контролю версій разом із package.json. Він фіксує точні версії пакетів і їхніх залежностей.
Для production-встановлення залежностей використовуйте:
npm ci --omit=devКоманда npm ci:
встановлює залежності відповідно до package-lock.json;
не змінює lock-файл;
призначена для чистого та повторюваного встановлення.
Параметр --omit=dev не встановлює залежності з devDependencies. Це доречно після завершення тестів і перевірок, якщо production-застосунку вони не потрібні під час виконання.
Типова послідовність на сервері може виглядати так:
npm ci
npm run check
npm prune --omit=dev
npm startАбо, якщо перевірки виконуються на етапі збірки:
npm ci
npm run check
npm ci --omit=dev
npm startКонкретна послідовність залежить від проєкту. Головне — не виконувати випадкове npm install у production замість повторюваного встановлення з lock-файла.
Змінна середовища — це значення, доступне процесу Node.js через process.env.
Наприклад:
const port = Number(process.env.PORT || 3000);
const nodeEnvironment = process.env.NODE_ENV || "development";У production зазвичай задають:
NODE_ENV=production
PORT=3000Значення з process.env завжди є рядками або undefined. Якщо потрібне число, його потрібно перетворити явно:
const port = Number(process.env.PORT);Не покладайтеся на неявне перетворення типів. Перевіряйте, що значення справді коректне.
Для кожної змінної варто визначити:
чи є вона обов’язковою;
яке значення використовується за замовчуванням;
допустимий формат;
чи містить вона секрет.
Наприклад:
PORT — необов’язкова, за замовчуванням 3000;
NODE_ENV — необов’язкова, за замовчуванням development;
DATABASE_URL — обов’язкова для production;
SESSION_SECRET — обов’язкова для production і повинна бути секретною.
Перевірка конфігурації під час запуску краща за пізню помилку під час першого запиту до бази даних.
Нижче наведено мінімальний Node.js-сервер без зовнішніх пакетів. Він:
читає PORT і NODE_ENV;
вимагає SESSION_SECRET у production;
відхиляє некоректний порт;
слухає всі мережеві інтерфейси;
має просту перевірку стану через /health.
Файл src/server.js:
import http from "node:http";
const nodeEnvironment = process.env.NODE_ENV ?? "development";
const portValue = process.env.PORT ?? "3000";
const port = Number(portValue);
if (!Number.isInteger(port) || port < 1 || port > 65535) {
console.error("Змінна PORT повинна бути цілим числом від 1 до 65535");
process.exit(1);
}
if (nodeEnvironment === "production" && !process.env.SESSION_SECRET) {
console.error("У production потрібно задати SESSION_SECRET");
process.exit(1);
}
const server = http.createServer((request, response) => {
if (request.url === "/health" && request.method === "GET") {
response.writeHead(200, { "content-type": "application/json" });
response.end(JSON.stringify({ status: "ok" }));
return;
}
response.writeHead(404, { "content-type": "application/json" });
response.end(JSON.stringify({ error: "Not found" }));
});
server.listen(port, "0.0.0.0", () => {
console.log(`Сервер запущено на порту ${port}`);
});Локальний запуск:
NODE_ENV=development PORT=3000 node src/server.jsProduction-запуск:
NODE_ENV=production PORT=3000 SESSION_SECRET='long-random-value' node src/server.jsПеревірка:
curl http://localhost:3000/healthОчікувана відповідь:
{"status":"ok"}0.0.0.0Якщо сервер слухає лише localhost, він може бути доступний тільки всередині самого процесу або машини. У контейнерному чи серверному середовищі зовнішній проксі може не мати доступу до нього.
Виклик:
server.listen(port, "0.0.0.0");дозволяє приймати з’єднання на всіх мережевих інтерфейсах. Доступ до застосунку все одно повинен контролюватися мережевим екраном, проксі або налаштуваннями інфраструктури.
До секретів належать:
паролі;
токени доступу;
ключі API;
рядки підключення до баз даних;
секрети для підпису сесій або токенів.
Секрети не повинні:
зберігатися в репозиторії;
потрапляти у package.json;
виводитися в журнали;
передаватися в повідомленнях комітів;
бути частиною Docker-образу;
включатися у звичайні приклади конфігурації.
Файл .env з локальними значеннями можна використовувати під час розробки, але його слід додати до .gitignore:
.env
.env.*
!.env.exampleФайл .env.example може містити лише назви змінних без реальних значень:
NODE_ENV=development
PORT=3000
DATABASE_URL=
SESSION_SECRET=Такий файл документує необхідну конфігурацію, але не розкриває секрети.
У production секрети передаються через механізм цільової інфраструктури:
секрет-сховище хмарного провайдера;
захищені змінні CI/CD;
змінні середовища процесу;
захищену конфігурацію платформи розгортання.
Застосунок не повинен знати, звідки саме взято секрет. Йому достатньо отримати значення через process.env.
Production-запуск повинен бути описаний у проєкті, а не залишатися неформальною інструкцією одного розробника.
Мінімальний приклад:
{
"scripts": {
"start": "node src/server.js",
"check": "node --check src/server.js"
}
}Команда npm start повинна запускати саме production-процес, а не режим розробки з автоматичним перезапуском або додатковими інструментами.
Перед запуском переконайтеся, що:
встановлено очікувану версію Node.js;
використано правильний commit або артефакт;
залежності встановлено з lock-файла;
задано всі обов’язкові змінні середовища;
застосунок слухає порт, який передала інфраструктура;
секрети не виводяться в журнали;
доступний endpoint перевірки стану.
Перед першим production-розгортанням складіть короткий план.
Визначте, що саме розгортається:
конкретний commit;
версія npm-пакета;
Docker-образ із тегом;
архів із вихідним кодом.
Не використовуйте невизначені позначення на кшталт latest, якщо неможливо встановити, який саме код зараз працює.
Перевірте:
версію Node.js;
наявність lock-файла;
сумісність залежностей;
наявність production-скрипта;
обов’язкові змінні середовища.
До запуску перевірте код і тести, якщо вони є в проєкті:
npm ci
npm run check
npm testЯкщо команда npm test не визначена в package.json, її не слід вигадувати для конкретного проєкту. Додайте лише ті перевірки, які справді налаштовані.
Задайте змінні середовища через production-конфігурацію. Не копіюйте .env вручну між серверами без контролю доступу та аудиту.
Запустіть процес командою, визначеною в package.json:
npm startУ production процес має запускатися менеджером процесів, системним сервісом або контейнерною платформою, яка може:
перезапустити процес після збою;
передати змінні середовища;
зібрати журнали;
повідомити про стан процесу.
Після запуску перевірте:
чи процес не завершився одразу;
чи endpoint перевірки стану повертає успішну відповідь;
чи немає помилок конфігурації в журналах;
чи доступні потрібні зовнішні залежності;
чи новий процес отримує трафік.
Розгортання повинно мати не лише шлях уперед, а й план повернення.
Перед оновленням визначте:
як ідентифікується поточна версія;
де зберігається попередній артефакт;
як швидко запустити попередню версію;
чи сумісні зміни конфігурації та даних;
які журнали потрібно перевірити після оновлення.
Якщо нова версія не запускається через відсутню змінну, несумісну версію Node.js або помилку залежності, повернення має бути простим: знову запустити попередній перевірений артефакт із відповідною конфігурацією.
Не видаляйте попередню версію одразу після оновлення, доки не переконаєтеся, що нова працює стабільно.
Журнали допомагають зрозуміти, чи успішно стартував застосунок і чому він завершився.
У журналах варто фіксувати:
факт запуску;
версію застосунку;
середовище;
критичні помилки конфігурації;
завершення процесу.
Не виводьте:
DATABASE_URL;
SESSION_SECRET;
токени;
повні заголовки авторизації;
персональні дані користувачів.
Приклад безпечного повідомлення:
console.log("Застосунок запущено", {
environment: nodeEnvironment,
port
});Не виводьте весь об’єкт process.env, оскільки він може містити секрети.
Приклад файлів проєкту:
production-app/
├── package.json
├── package-lock.json
├── .nvmrc
├── .env.example
└── src/
└── server.jsДо репозиторію зазвичай додають:
вихідний код;
package.json;
package-lock.json;
.nvmrc;
.env.example;
інструкції запуску.
Не додають:
.env із реальними значеннями;
каталоги залежностей;
локальні журнали;
тимчасові файли;
приватні ключі.
Без lock-файла різні середовища можуть отримати різні версії залежностей.
Як уникнути: зберігайте package-lock.json у репозиторії та використовуйте npm ci.
Застосунок локально запускається на одній версії Node.js, а production використовує іншу.
Як уникнути: зафіксуйте версію через .nvmrc, engines або базовий образ і перевіряйте її під час розгортання.
Секрет, який потрапив у Git, може залишитися в історії навіть після видалення файлу.
Як уникнути: використовуйте секрети інфраструктури та додайте .env до .gitignore. Якщо секрет уже опубліковано, його потрібно відкликати й створити новий.
Застосунок завжди слухає порт 3000, хоча production-платформа передає інший порт.
Як уникнути: читайте process.env.PORT і перевіряйте значення.
localhostПроцес працює, але зовнішній проксі або контейнер не може до нього підключитися.
Як уникнути: для відповідних середовищ слухайте 0.0.0.0.
Команди для розробки можуть вмикати автоматичний перезапуск, зайве журналювання або непотрібні залежності.
Як уникнути: окремо визначте production-команду npm start.
Застосунок стартує, але падає лише після першого запиту до зовнішнього сервісу.
Як уникнути: перевіряйте обов’язкові змінні під час запуску і завершуйте процес із зрозумілим повідомленням.
Налагоджувальний console.log(process.env) може розкрити всі секрети.
Як уникнути: журналюйте лише безпечні поля та ніколи не друкуйте конфігурацію повністю.
Для надійного розгортання Node.js-застосунку:
зафіксуйте версію Node.js;
зберігайте lock-файл у репозиторії;
встановлюйте production-залежності повторюваною командою npm ci;
передавайте конфігурацію через змінні середовища;
зберігайте секрети поза кодом і репозиторієм;
перевіряйте обов’язкові змінні під час запуску;
використовуйте production-команду npm start;
забезпечте доступність потрібного порту;
перевіряйте стан застосунку після розгортання;
зберігайте попередню версію для швидкого повернення.