01 / 対応版と既存環境を確認
Ubuntu Server 22.04の物理マシン・仮想マシンで、Node.js 24 LTSを導入します。管理者とSSH、更新とバックアップを済ませ、sudoと復旧コンソールを用意してください。特記以外、サーバーの一般管理者で操作します。PHP・Laravel・WordPressとは独立した実行環境で、PostgreSQLの導入も必須ではありません。
Node.js公式のリリース一覧で対応版と保守期間を確認します。Ubuntu 22.04の標準パッケージが現在のアプリ要件に合うとは限らないため、この例はNodeSourceの24系を使います。26系など別メジャーへ無条件に変更しません。
Ubuntu公式・Node.js公式のAPTリポジトリではありません。組織の利用方針と更新管理を確認してください。追加した鍵はsigned-byでこの配布元に限定します。
command -v node npm || true
node --version
npm --version
apt-cache policy nodejs npm
sudo ss -lntp未導入ならコマンドが見つからない状態です。既存Node.js、nvm等のバージョン管理、npmパッケージ、動作中アプリがあれば、この新規導入例をそのまま重ねず、移行計画を立てます。NodeSource版nodejsはnpmを含むため、Ubuntuのnpmを別途追加しません。
02 / 署名付きAPTで導入
APTを退避し、HTTPS取得と鍵の確認に使うツールを準備します。同名の鍵・ソースが既にあれば上書きせず確認してください。
BACKUP="$(sudo mktemp -d /root/server-guide-node-apt.XXXXXX)" &&
sudo cp -a /etc/apt "$BACKUP/"
printf '保存先: %s\n' "$BACKUP"
sudo apt-get update && sudo apt-get install ca-certificates curl gnupg
WORKDIR="$(mktemp -d)"
curl --fail --show-error --location --output "$WORKDIR/nodesource.key" https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key
gpg --show-keys --with-fingerprint "$WORKDIR/nodesource.key"NodeSourceの導入案内で取得先を照合し、鍵の変更がないか確認します。実測した主鍵指紋は6F71F525282841EEDAF851B42F59B5F99B1BE0B4です。指紋の表示だけでは所有者を独立に認証したことになりません。公式案内の取得先と照合し、変更があれば理由を調べてから続けます。以下は鍵取得元を確認でき、同名設定が存在しない場合に実行します。TLSや署名のエラーを無効化して進めないでください。
sudo test ! -e /usr/share/keyrings/nodesource.gpg &&
sudo test ! -e /etc/apt/sources.list.d/nodesource.list &&
sudo gpg --dearmor --output /usr/share/keyrings/nodesource.gpg "$WORKDIR/nodesource.key" &&
sudo chmod 644 /usr/share/keyrings/nodesource.gpg &&
printf '%s\n' 'deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_24.x nodistro main' | sudo tee /etc/apt/sources.list.d/nodesource.list >/dev/null
sudo apt-get update
apt-cache policy nodejs
sudo apt-get -s install nodejs候補がNodeSourceの24系で、削除・更新予定が意図した範囲か確認してから導入します。シミュレーションが成功しても、既存アプリへの無影響は保証しません。
sudo apt-get --no-remove install nodejs
node --version
npm --version
command -v node npm
apt-cache policy nodejsnodeがv24系、npmの版と実行ファイルを確認します。追加リポジトリが既存の自動更新設定に含まれるとは限りません。保守時間にAPTの候補とアプリテストを確認して更新する運用を決めます。
03 / 一般ユーザーでアプリを用意
次ページでサービス化する、小さなHTTPアプリを作ります。Node.js組込み機能だけを使い、外部依存はありません。既存ディレクトリがある場合は停止して内容を確認します。npmはsudoで実行しません。
test ! -e "$HOME/node-guide-work" &&
mkdir -m 750 "$HOME/node-guide-work" &&
cd "$HOME/node-guide-work"
cat > package.json <<'JSON'
{"name":"node-guide","version":"1.0.0","private":true,"scripts":{"start":"node server.cjs","test":"node --test"}}
JSONserver.cjsとテストは次の例を保存します。外部の入力やファイルを公開する機能は持たせず、待受先はループバックに固定します。
cat > server.cjs <<'JS'
'use strict';
const http = require('node:http');
function createAppServer() {
return http.createServer((req, res) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
if (req.method !== 'GET') {
res.writeHead(405, { Allow: 'GET', 'Content-Type': 'text/plain; charset=utf-8' });
return res.end('Method not allowed\n');
}
if (req.url === '/health') {
res.writeHead(200, { 'Content-Type': 'application/json' });
return res.end(JSON.stringify({ status: 'ok' }) + '\n');
}
if (req.url === '/') {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
return res.end('<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Node.js guide</title><body><h1>Node.js is ready</h1><p>Ubuntu Server 22.04 / Node.js HTTP application</p></body></html>\n');
}
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('Not found\n');
});
}
if (require.main === module) {
const port = Number(process.env.PORT || 3001);
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error('Invalid PORT');
const server = createAppServer();
server.listen(port, '127.0.0.1', () => console.log(`Listening on 127.0.0.1:${port}`));
process.on('SIGTERM', () => server.close(() => process.exit(0)));
}
module.exports = { createAppServer };
JScat > server.test.cjs <<'JS'
'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const { once } = require('node:events');
const { createAppServer } = require('./server.cjs');
test('HTTP routes and methods', async () => {
const server = createAppServer();
server.listen(0, '127.0.0.1');
await once(server, 'listening');
const base = `http://127.0.0.1:${server.address().port}`;
try {
const home = await fetch(base + '/');
assert.equal(home.status, 200);
assert.match(await home.text(), /Node.js is ready/);
const health = await fetch(base + '/health');
assert.equal(health.status, 200);
assert.deepEqual(await health.json(), { status: 'ok' });
assert.equal((await fetch(base + '/missing')).status, 404);
const post = await fetch(base + '/', { method: 'POST' });
assert.equal(post.status, 405);
assert.equal(post.headers.get('allow'), 'GET');
} finally {
server.close();
await once(server, 'close');
}
});
JS04 / テストと完了条件
依存の固定用にlockfileを生成し、それを使った導入とテストを一般ユーザーで実行します。外部依存のない例でも、実アプリではlockfileをGitへ保存し、信頼できるコードをレビューしてからnpm ciを実行してください。この例はインストールスクリプト不要なので、--ignore-scriptsで実行を抑止します。実アプリでスクリプトが必要な場合は、内容と依存を確認して利用者権限で実行する設計にしてください。
cd "$HOME/node-guide-work"
npm install --package-lock-only --ignore-scripts
npm ci --ignore-scripts
npm test
node --check server.cjsすべて終了コード0で、HTTP正常応答・ヘルスチェック・404・405のテストが成功したら準備完了です。ここでは開発用のシェル起動を常駐運用に使いません。専用ユーザーでのサービス化とWeb公開設定へ進みます。
05 / 問題時の調査と戻し方
取得に失敗したら日時・DNS・プロキシ・公式配布元を調べ、TLS検証やAPT署名を無効にしないでください。別のnodeが選ばれる場合はPATHとバージョン管理ツールを確認します。テスト失敗を無視して常駐させません。
追加ソースを退避してAPTを更新するだけでは、導入済みNode.jsは元の版に戻りません。APT履歴と退避した設定を基に、利用アプリ・npmの対応・バックアップを確認して復旧します。使用中のnodejsを一括削除しません。次ページのサービスを導入済みなら、先にその公開設定とサービスを停止して影響を確認します。
