小さく制御された環境を準備する
この手順は、systemd、管理者アカウント、すでにインストールされたNode.js 24 LTSランタイム、curl、Caddyのパッケージ化されたシステムサービスを備えたLinuxシステムを対象としています。まずインストールされているバージョンとパッケージパスを確認してください。 Nodeのリリースページ でサポートされているリリースラインを確認できます。インストールとプロバイダーのプロビジョニングは別のタスクです。自分が管理するマシンを使用し、テスト済みのSSHセッションと復旧パスを利用可能にしておいてください。名前 first-api と /opt/first-api はこの例を作成する前に未使用である必要があります。
HTTPSには、管理するドメイン、正しいA/AAAAレコード、Webトラフィックを公開する権限も必要です。 api.example.com 以下は予約された例です。自分のホスト名に置き換えてください。このAPIにはデータベース、認証、顧客データは意図的に含まれていません。これは再現可能なプロセスを示すものであり、完全な製品やテスト済みのOffVPSデプロイではありません。
ランタイムを確認し、1つのリリースを作成する
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();
});
明示的なループバックアドレスにより、APIリスナーはサーバー自体に留まります。Caddyがその公開エントリポイントになります。 Node HTTP API でリクエスト処理、タイムアウト、サーバーシャットダウンについて説明しています。実際に実行するアカウントとしてファイルを確認してください:
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
ユニットは1つの専用ユーザー、明示的な実行ファイル、バージョン管理された作業ディレクトリを使用します。自動復旧はレート制限されており、意図的なサービス停止は 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
「 && ガードはコマンドが失敗したときに貼り付けたシーケンスを停止します。開始前に検証警告を解決し、チェックが失敗した後に次のブロックに進まないでください。 ユニット検証 は構文と実行ファイルの問題を検出できますが、チェックの成功はアプリケーションが動作している証明ではありません。期待されるヘルス応答は {"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をプライベートに保ってください。これらの要件は Caddy自動HTTPSに由来します。アップストリームの構文は 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を返すことを確認してください。
既知のリリースと安全な停止ポイントを保持する
両方のチェックが機能したら、 sudo systemctl enable first-api.serviceで将来の起動のためにAPIを有効にしてください。ランタイムバージョン、ソースファイル、ユニット、Caddy設定を記録してください。次のリリースでは、新しい番号付きディレクトリを作成し、サービスユーザーとして構文チェックし、両方のユニットパスを更新し、systemdをリロードしてAPIを再起動してください。新しいリリースが受け入れられるまで前のディレクトリを保持してください。
この例を停止するには、 sudo systemctl stop first-api.serviceを使用してください。そのルートが設定されている間、Caddyはアップストリーム障害を報告します。廃止するときはこのルートのみを削除し、Caddyを検証/リロードしてください。失敗したコードリリースは、前のユニットパスを選択してチェックを繰り返すことでロールバックしてください。後のデータベースマイグレーションには独自の復旧計画が必要です。次に進んでください: DNSからアプリケーションへのリクエストパス または アプリが停止した理由の特定.
使用したドキュメント
このページの主な参照資料。ご自身の環境にインストールされているバージョンのドキュメントを確認してください。