OffVPSOFFSHORE VPSПоддержка

Развёртывание приложения

Дайте вашему первому API воспроизводимый выпуск.

Заставьте небольшой API работать локально, сделайте его процесс восстановимым и только затем подключите его имя хоста и HTTPS. Держите путь релиза и путь назад явными.

Полевое руководство OffVPS · Проверено · 5 мин чтения

Подготовьте небольшую контролируемую среду

Эта процедура рассчитана на систему Linux с systemd, учётной записью администратора, уже установленной средой выполнения Node.js 24 LTS, curl и пакетной системной службой Caddy. Сначала подтвердите установленные версии и пути пакетов; страница релизов Node определяет поддерживаемые линии релизов. Установка и подготовка провайдером — отдельные задачи. Используйте машину, которую контролируете, и держите наготове проверенный сеанс SSH и путь восстановления. Имена first-api и /opt/first-api должны быть неиспользованными перед созданием этого примера.

Для HTTPS также нужен домен, который вы контролируете, корректные A/AAAA-записи и разрешение открывать веб-трафик. api.example.com ниже — зарезервированный пример: замените его своим именем хоста. Это API намеренно не содержит базы данных, аутентификации или данных клиентов. Оно демонстрирует повторяемый процесс, а не готовый продукт или протестированное развёртывание OffVPS.

Проверьте среду выполнения и создайте один релиз

command -v node &&
readlink -f "$(command -v node)" &&
node --version

Остальная часть примера предполагает, что проверенный общий исполняемый файл — это /usr/bin/node. Если у вас другой, замените этот путь в каждой проверке и в ExecStart. Среда выполнения в приватном домашнем каталоге вашего пользователя входа не становится автоматически доступной системной службе. Создайте служебную учётную запись и принадлежащий root каталог релиза, останавливаясь при обнаружении неожиданной существующей учётной записи или пути.

sudo useradd --system --user-group --home-dir /opt/first-api \
  --shell /usr/sbin/nologin first-api &&
sudo install -d -o root -g root -m 0755 /opt/first-api/releases/001

С помощью редактора с административным доступом сохраните следующее как /opt/first-api/releases/001/server.mjs, принадлежащее root и читаемое служебным пользователем. Релиз содержит только этот файл; здесь нет зависимостей пакетов или секретов.

import http from 'node:http';

const port = Number(process.env.PORT || 3000);
if (!Number.isInteger(port) || port < 1024 || port > 65535) {
  throw new Error('PORT must be an integer from 1024 to 65535');
}
const server = http.createServer((req, res) => {
  res.setHeader('Content-Type', 'application/json; charset=utf-8');
  res.setHeader('Cache-Control', 'no-store');
  if (req.method !== 'GET') {
    res.writeHead(405, { Allow: 'GET' });
    res.end(JSON.stringify({ error: 'method_not_allowed' }));
    return;
  }
  if (req.url === '/healthz') {
    res.writeHead(200);
    res.end(JSON.stringify({ status: 'ok', release: '001' }));
  } else if (req.url === '/api/message') {
    res.writeHead(200);
    res.end(JSON.stringify({ message: 'A small app, running clearly.' }));
  } else {
    res.writeHead(404);
    res.end(JSON.stringify({ error: 'not_found' }));
  }
});
server.requestTimeout = 10000;
server.headersTimeout = 10000;
server.keepAliveTimeout = 5000;
server.listen(port, '127.0.0.1');
process.on('SIGTERM', () => {
  server.close(() => process.exit(0));
  setTimeout(() => process.exit(1), 10000).unref();
});

Явный адрес loopback удерживает слушателя API на самом сервере. Caddy будет его публичной точкой входа. HTTP API Node документирует обработку запросов, тайм-ауты и завершение работы сервера. Проверьте файл от имени учётной записи, которая фактически будет его выполнять:

sudo -u first-api /usr/bin/node --check /opt/first-api/releases/001/server.mjs

Дайте процессу определение службы

Сохраните /etc/systemd/system/first-api.service с этим содержимым:

[Unit]
Description=First API learning release
After=network.target
StartLimitIntervalSec=60
StartLimitBurst=5

[Service]
Type=simple
User=first-api
Group=first-api
WorkingDirectory=/opt/first-api/releases/001
ExecStart=/usr/bin/node /opt/first-api/releases/001/server.mjs
Environment=NODE_ENV=production
Environment=PORT=3000
Restart=on-failure
RestartSec=5
TimeoutStopSec=15
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true

[Install]
WantedBy=multi-user.target

Модуль использует одного выделенного пользователя, явный исполняемый файл и версионированный рабочий каталог. Автоматическое восстановление ограничено по частоте; намеренная остановка службы не запускает Restart=on-failure. См. systemd.service. Ограничения файловой системы подходят для этого API только для чтения; приложению, которое записывает данные, нужно намеренно ограниченное записываемое хранилище. Секретам не место в этих строках окружения. См. настройки выполнения systemd.

sudo systemd-analyze verify /etc/systemd/system/first-api.service &&
sudo systemctl daemon-reload &&
sudo systemctl start first-api.service &&
sudo systemctl status first-api.service --no-pager &&
curl --fail --show-error http://127.0.0.1:3000/healthz

The && защитные механизмы останавливают вставленную последовательность при сбое команды. Устраните предупреждения проверки перед запуском и не переходите к следующему блоку после неудачной проверки. Проверка модуля может выявить проблемы синтаксиса и исполняемого файла, но успешная проверка не доказывает работу приложения. Ожидаемый ответ проверки здоровья — {"status":"ok","release":"001"}. Если он не проходит, изучите sudo journalctl -u first-api.service -n 50 --no-pager прежде чем многократно перезапускать.

Добавьте маршрут HTTPS после локальной проверки

Сделайте резервную копию существующей конфигурации Caddy под неиспользуемым именем файла. Добавьте этот блок в /etc/caddy/Caddyfile не заменяя несвязанные сайты:

api.example.com {
    reverse_proxy 127.0.0.1:3000
}

Для стандартного потока с публичным доменом имя хоста должно разрешаться в сервер, порты 80/443 должны достигать Caddy, а хранилище сертификатов Caddy должно оставаться записываемым и постоянным. Проверьте каждый опубликованный маршрут A/AAAA. Оставьте доступ SSH нетронутым и держите порт 3000 приватным. Эти требования взяты из Автоматический HTTPS в Caddy; синтаксис upstream задокументирован в reverse_proxy.

sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile &&
sudo systemctl reload caddy.service

Перезагружайте только после успешной проверки; caddy validate проверяет адаптированную конфигурацию. Рабочий процесс пакетной службы описан в руководстве по службе Caddy. С отдельного клиента запросите https://api.example.com/healthz используя ваше реальное имя хоста. Ожидайте доверенное TLS-соединение и тот же ответ релиза без обхода проверок сертификата. Затем проверьте, что /api/message возвращает своё сообщение, а неизвестный путь возвращает 404.

Сохраните известный релиз и безопасную точку остановки

После успешной работы обеих проверок включите API для будущих загрузок с помощью sudo systemctl enable first-api.service. Запишите версию среды выполнения, исходный файл, модуль и конфигурацию Caddy. Для следующего релиза создайте новый нумерованный каталог, проверьте его синтаксис от имени служебного пользователя, обновите оба пути модуля, перезагрузите systemd и перезапустите API. Сохраняйте предыдущий каталог, пока новый релиз не будет принят.

Чтобы остановить этот пример, используйте sudo systemctl stop first-api.service. Caddy сообщит об отказе upstream, пока этот маршрут остаётся настроенным; при выводе из эксплуатации удалите только этот маршрут и проверьте/перезагрузите Caddy. Откатите неудачный релиз кода, выбрав предыдущие пути модуля и повторив проверки. Более поздняя миграция базы данных требует собственного плана восстановления. Продолжите с путь запроса от DNS к приложению или выяснение, почему приложение остановилось.

Использованная документация

Основные ссылки для этой страницы. Проверьте документацию для версии, установленной в вашей среде.