ラズパイで作る自宅WEBサーバ:nginx編
第9回 Node.js設定
2026.11.02
Node.js は、JavaScriptをサーバ上でも実行できるようにしたJavaScript動作環境です。
エンジンエックスは、3000番ポートを介してローカル環境で実行しているNode.jsサーバを呼び出します。
●Node.js インストール
Ubuntu 24.04にNode.jsをインストールするには、公式リポジトリではなくNodeSourceのリポジトリを使うのが一番簡単です。
NodeSourceリポジトリを追加します。
$ curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
Node.jsをインストールします。
$ sudo apt-get install -y nodejs
バージョンを確認します。
$ node -v
v20.20.2
Node.jsと一緒に、npm (Node Package Manager) もインストールされます。バージョンを確認します。
$ npm --version
10.8.2
●送信元IPアドレスの取得
Nginxをリバースプロキシとして使用する場合、Node.jsで取得できる接続元IPはすべてNginxのアドレス(127.0.0.1等)になってしまいます。
解決には、Nginx側で X-Forwarded-For ヘッダーを付与し、そのヘッダーを読み取る必要があります。
$ sudo vi /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
worker_cpu_affinity auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
server {
listen 80;
server_name 192.168.11.28;
root /example/www;
location /exercise {
# Node.jsアプリケーションへリクエストを転送
proxy_pass http://localhost:3000;
# ヘッダー設定
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
# 接続元IPをヘッダーに追加
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
ここでは、簡単のために、server_name にIPアドレスを使用していますが、DNS設定をしている場合はドメイン名に置き換えてください。
$ sudo nginx -t
$ sudo systemctl restart nginx
クライアントからのリクエストを処理するサーバ側コードを作成します。
$ mkdir /example/www/exercise
$ chmod 755 -R /example/www/exercise
$ vi /example/www/exercise/index.js
const http = require("http");
const server = http.createServer((req, res) => {
// プロキシ環境下で実際のIPを取得する場合
var forwarded_ip = '0.0.0.0';
if (req.headers['x-forwarded-for']) {
forwarded_ip = req.headers['x-forwarded-for'];
};
// 1. リクエストURLからベースURLを補ってURLオブジェクトを作成
const baseURL = `http://${req.headers.host}`;
const url = new URL(req.url, baseURL);
const params = url.searchParams;
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.write(`Remote IP Address: ${forwarded_ip}\n`);
res.write(`Domain IP Address: ${req.headers.host}\n`);
res.write(`Path: ${req.url}\n`);
// 2.1 searchParams.get('キー名') でGETパラメータを取得
const name = params.get('name'); // 例: ?name=taro なら "taro"
const age = params.get('age'); // 例: ?age=20 なら "20"
res.write(`名前: ${name}, 年齢: ${age}\n`);
// 2.2 すべての引数名と値の一覧を取得する
for (const [key, value] of params.entries()) {
res.write(`${key}: ${value}\n`);
}
res.end();
});
server.listen(3000);
変数の値を表示したいのに、バッククォートではなくシングルクォートやダブルクォートで囲んでいると、
変数名がそのまま出力されてしまいます。
●nodemon

Node.jsは一度読み込んだファイルをメモリにキャッシュするため、コードを書き換えても再起動しないと反映されません。
nodemon はコードの変更を監視して自動でサーバーを再起動してくれるツールです。
サイト開発時、頻繁にソースコードの書換えが発生する場合に便利です。
nodemon インストール
Node.jsで実行されるコードを置いているディレクトリに移動します。
$ cd /example/www/exercise
開発環境のみで使用するので--save-devを付けてインストールします。
$ npm install nodemon --save-dev
added 28 packages in 11s
5 packages are looking for funding
run `npm fund` for details
node_modulesディレクトリとpackage-lock.json,package.json が生成されます。
$ ls -l
drwxrwxr-x 31 pi pi 4096 Oct 10 19:01 node_modules
-rw-rw-r-- 1 pi pi 56 Oct 10 19:01 package.json
-rw-rw-r-- 1 pi pi 12815 Oct 10 19:01 package-lock.json
package.jsonの内容をみてみます
$ cat package.json
{
"devDependencies": {
"nodemon": "^3.1.14"
}
}
通常のインストールでは、"dependencies"セクション内に記述されます。ここには実行時に必要なライブラリを配置します。
--save-dev オプションを付けると、"devDependencies"内に開発時にのみ必要なライブラリが追加されます。
npm start でスクリプト(index.js)を起動できるように package.json に追記します。
$ vi package.json
{
"devDependencies": {
"nodemon": "^3.1.14"
},
"scripts": {
"start": "nodemon index.js"
}
}
nodemonを起動します。root権限(sudo)での起動は避けましょう。
$ npm start
> start
> nodemon index.js
[nodemon] 3.1.14
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node index.js`
別のターミナルからindex.jsを変更すると
[nodemon] restarting due to changes...
[nodemon] starting `node index.js`
変更が反映されてリスタートします。
nodemonを一般権限(管理者権限やroot権限ではない状態)で動かしている場合でも、Node.jsのプロセスを再起動することが可能です。
nodemonは自身が起動したNode.jsの子プロセス(Child Process)としてNode.jsを管理しています。
そのため、一般権限であっても、自分が起動したプロセスに対してであれば、終了や再起動のシグナルを送る権限を持っています。
再起動の仕組み
1. ファイルの変更を検知: nodemonが監視対象のファイル変更をキャッチします。
2. 古いプロセスの終了: nodemonは自身が立ち上げたNode.jsプロセスに対して終了シグナル(通常はSIGUSR2やSIGINT)を送り、安全にプロセスを終了させます。
3. 新しいプロセスの起動: 古いプロセスが終了した後、同じ一般権限のまま再び新しいNode.jsプロセスを立ち上げます。
このように、すべて同じユーザー権限の範囲内で処理が完結するため、特別な管理者権限(sudoなど)は必要ありません。
ブラウザからアクセスします
http://192.168.11.28/exercise?name=taro&age=21

Remote IP Address: 192.168.11.77 はブラウザを開いているパソコンのアドレスです。
クライアントからのリクエストを取得して表示しています。
nodemonを停止するには、nodemonを起動したターミナルで [Ctrl] + C を押します。
本番環境に移行する際は、nodemonを無効にします。
$ npm install --omit=dev
※--productionは--omit=devのエイリアスで、非推奨です。
package.jsonのdevDependencies"セクションに記載されていたnodemonモジュールが削除され、
node_moduleディレクトリ内が空になります。
明示的に nodemon を削除する場合
$ npm uninstall nodemon
●Nginxによる非SSL化
実際の運用ではHTTPSでのリクエストは、nginx側で非SSL化されたうえで
HTTPでバックエンドのNode.jsへ転送(リバースプロキシ)しています。
server {
listen 443 ssl;
server_name example.com;
# SSL証明書と秘密鍵の設定
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
proxy_pass http://localhost:3000; # Node.jsが動いているポート
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
# クライアントの実際のIPやプロトコル情報をNode.js側に伝えるヘッダー
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
主要な設定のポイント
• listen 443 ssl;: 外部からのHTTPS通信(443番ポート)をNginxで受け取ります。
• ssl_certificate / ssl_certificate_key: Let's Encryptなどで取得したSSL証明書と秘密鍵を指定します。
• proxy_pass http://localhost:3000;: Nginxが復号したデータを、内部で動くNode.js(例: ポート3000)へHTTPで転送します。
• X-Forwarded-Proto $scheme: Node.js側で「今アクセスされているのが元々HTTPSだったか」を判別できるようにする重要なヘッダーです。
●PM2 (Process Manager 2)インストール

本番環境では、PM2を実装します。
PM2は、JavaScript ランタイムである Node.js用のプロセスマネージャーです。
リクエストの流れ
1. ブラウザから Nginx(80/443番)にアクセスが来ます
2. Nginx が proxy_pass http://localhost:3000; によって、リクエストをローカルの3000番へ転送(リバースプロキシ)します。
3. PM2によってバックグラウンドで起動されているNode.js が、その3000番ポートでリクエストを受け取って処理します。
3000番ポートを制御(リッスン)してリクエストを受け取るのは、PM2ではなくNode.jsアプリケーション(app.listen(3000))自体です。
PM2はNode.jsアプリがエラーで落ちたら自動再起動し、ログを管理します。(※PM2自身は3000番ポートを使いません)
※例外(PM:クラスターモードの場合)
PM2の「クラスターモード(-i max など)」を使って、複数のNode.jsプロセスを同時に動かす場合、一見するとPM2がポートを制御しているように見えます。
この場合、PM2(内部のロードバランサーモジュール)がシステム的に3000番ポートを代表して受け取り、配下の複数のNode.jsプロセスに処理を自動で振り分けます。ただし、これも「Node.jsアプリを動かすための仕組み」の一部であり、PM2という独立したWebサーバーがポートを奪っているわけではありません。
$ sudo npm install -g pm2
PM2 環境設定ファイル作成
$ sudo vi /etc/nginx/pm2.config.js
module.exports = {
apps : [
{
name: "Node.js script(3000)",
script: "./index.js",
cwd : '/example/www/exercise/',
exec_mode: 'fork',
instances: 1,
max_memory_restart: '50M',
// exec_mode: 'cluster',
// instances: -1,
// max_memory_restart: '500M',
interpreter: '/usr/bin/node',
env: {
PORT: 3000,
NODE_ENV: "local",
}
}
]
}
| name |
適当な名前を付けておきます。( )でポート番号を明記しておくとわかりやすいです。 |
| script |
実行コマンドを指定するのですが、jsファイルを指定した場合、自動的にnode.jsと判断して、nodeで実行してくれます。 |
| cwd |
実行時のカレントディレクトリを指定します。scriptで指定するNode.jsファイルの位置に合わせます。 |
| instances |
max or 0: 利用可能なすべてのCPUコアにプロセスを分散させる。
-1: すべてのCPUコア数から-1した数を起動する
(マスタープロセス用に1つ空けたい場合に便利)。
|
| exec_mode |
"fork"(default):Node.jsのプロセスを1つだけ起動します。シンプルなアプリケーションやスクリプトに向いています。
"cluster":コードを書き換えることなくNode.jsアプリをすべてのCPUコアに分散し、ゼロダウンタイムでリクエストの負荷分散(ロードバランシング)を行えます。
|
| interpreter |
デフォルトは node のため、標準のNode.jsアプリであれば省略可能です。
Node.jsをaptコマンドでインストールした場合、実行ファイルは /usr/bin/node |
| max_memory_restart |
Node.jsアプリケーションのメモリリーク対策として設定します。
'500M'(500メガバイト)や '1G'(1ギガバイト)のように指定し、上限を超えるとPM2が自動的にプロセスを再起動します。 |
設定ファイルに従ってpm2を起動します。
$ sudo pm2 start /etc/nginx/pm2.config.js
【exec_mode = "fork"の場合】
[PM2] Applying action restartProcessId on app [Node.js script(3000)](ids: [ 0 ])
[PM2] [Node.js script(3000)](0) ?
+----+---------------------+----------+------+-----------+----------+---------+
| id | name | mode | ? | status | cpu | memory |
+----+---------------------+----------+------+-----------+----------+---------+
| 0 | Node.js script(30… | fork | 1 | online | 0% | 23.5mb |
+----+---------------------+----------+------+-----------+----------+---------+
host metrics | cpu: 0.3% | ram usage: 8% |
【exec_mode = "cluster"の場合】
[PM2] Spawning PM2 daemon with pm2_home=/root/.pm2
[PM2] PM2 Successfully daemonized
[PM2][WARN] Applications Node.js script(3000) not running, starting...
[PM2] App [Node.js script(3000)] launched (3 instances)
+----+---------------------+----------+------+-----------+----------+---------+
| id | name | mode | ? | status | cpu | memory |
+----+---------------------+----------+------+-----------+----------+---------+
| 0 | Node.js script(30… | cluster | 0 | online | 0% | 48.1mb |
| 1 | Node.js script(30… | cluster | 0 | online | 0% | 46.6mb |
| 2 | Node.js script(30… | cluster | 0 | online | 0% | 43.3mb |
+----+---------------------+----------+------+-----------+----------+---------+
host metrics | cpu: 0% | ram usage: 50.8% |
cluster modeの場合の Node.jsアプリ起動状態を表示してみます。
$ sudo pm2 status
+----+----------------------+-----------+---------+---------+------+--------+----+--------+-----+--------+------+----------+
| id | name | namespace | version | mode | pid | uptime | ? | status | cpu | mem | user | watching |
+----+----------------------+-----------+---------+---------+------+--------+----+--------+-----+--------+------+----------+
| 0 | Node.js script(3000) | default | N/A | cluster | 2153 | 2m | 0 | online | 0% | 42.4mb | root | disabled |
| 1 | Node.js script(3000) | default | N/A | cluster | 2160 | 2m | 0 | online | 0% | 41.9mb | root | disabled |
| 2 | Node.js script(3000) | default | N/A | cluster | 2171 | 2m | 0 | online | 0% | 46.2mb | root | disabled |
+----+----------------------+-----------+---------+---------+------+--------+----+--------+-----+--------+------+----------+
host metrics | cpu: 0.7% | ram usage: 64.8% | disk: ? 0.037mb/s ? 0mb/s /snap/core24/1644 100% /snap/snapd/27407 100% |
Raspberry Pi 3のプロセッサーはクアッドコア(4コア)です。
PM2の設定ファイル pm2.config.js で instances: -1 にしたので、
Node.js に対して3つのクラスタが生成されています。
id = 0 の状態を表示してみます。cluster modeの場合は、0~2を指定可。
$ sudo pm2 show 0
pi@ns:~ $ sudo pm2 show 0
Describing process with id 0 - name Node.js script(3000)
+--------------------+--------------------------------------------------+
| status | online |
| name | Node.js script(3000) |
| namespace | default |
| version | N/A |
| restarts | 0 |
| max memory restart | 524288000 |
| uptime | 8m |
| script path | /example/www/exercise/index.js |
| script args | N/A |
| error log path | /root/.pm2/logs/Node.js-script-3000--error-0.log |
| out log path | /root/.pm2/logs/Node.js-script-3000--out-0.log |
| pid path | /root/.pm2/pids/Node.js-script-3000--0.pid |
| interpreter | /usr/bin/node |
| interpreter args | N/A |
| script id | 0 |
| exec cwd | /example/www/exercise |
| exec mode | fork_mode |
| node.js version | 20.20.2 |
| node env | local |
| watch & reload | ? |
| unstable restarts | 0 |
| created at | 2026-10-09T11:53:54.958Z |
+--------------------+--------------------------------------------------+
Actions available
+------------------------+
| km:heapdump |
| km:cpu:profiling:start |
| km:cpu:profiling:stop |
| km:heap:sampling:start |
| km:heap:sampling:stop |
+------------------------+
Trigger via: pm2 trigger Node.js script(3000)
Code metrics value
+------------------------+-----------+
| Active requests | 0 |
| Active handles | 1 |
| Event Loop Latency | 0.44 ms |
| Event Loop Latency p95 | 1.29 ms |
| Heap Size | 6.32 MiB |
| Heap Usage | 78.72 % |
| Used Heap Size | 4.97 MiB |
| HTTP Mean Latency | 131 ms |
| HTTP P95 Latency | 131 ms |
| HTTP | 0 req/min |
+------------------------+-----------+
Divergent env variables from local env
+------------------------------------------------------------------+
| SUDO_COMMAND x /usr/local/bin/pm2 start /etc/nginx/pm2.config.js |
+------------------------------------------------------------------+
Add your own code metrics: http://bit.ly/code-metrics
Use `pm2 logs Node.js script(3000) [--lines 1000]` to display logs
Use `pm2 env 0` to display environment variables
Use `pm2 monit` to monitor CPU and Memory usage Node.js script(3000)
ログファイルは、特に指定がない場合、実行ユーザの以下のフォルダに格納されます。
~/.pm2/logs/
各Node.jsアプリごとに生成され、ログファイル名は、pm2 show [id] で確認できます。
pm2の自動実行設定
OS起動時に、pm2が自動起動するようにします。
$ sudo pm2 startup
サービスファイル(pm2-root.service)が自動生成されます。
サービスファイルを複写して、権限を書き換えます。
$ sudo cp /etc/systemd/system/pm2-root.service /etc/systemd/system/pm2.service
$ sudo chmod 664 /etc/systemd/system/pm2.service
一旦、OS起動時の自動起動(スタートアップスクリプト)を無効化します。
$ sudo pm2 unstartup systemd
[PM2] Init System found: systemd
Removed '/etc/systemd/system/multi-user.target.wants/pm2-root.service'.
Removed '/etc/systemd/system/multi-user.target.wants/pm2-root.service'.
[PM2] Init file disabled.
サービスファイルを書き換えてpm2起動時に設定ファイルを読み込むようにします。
$ sudo vi /etc/systemd/system/pm2.service
ExecStart=/usr/local/lib/node_modules/pm2/bin/pm2 resurrect
ExecReload=/usr/local/lib/node_modules/pm2/bin/pm2 reload all
ExecStop=/usr/local/lib/node_modules/pm2/bin/pm2 kill
↓変更
#ExecStart=/usr/local/lib/node_modules/pm2/bin/pm2 resurrect
ExecStart=/usr/local/lib/node_modules/pm2/bin/pm2 start /etc/nginx/pm2.config.js
#ExecReload=/usr/local/lib/node_modules/pm2/bin/pm2 reload all
ExecReload=/usr/local/lib/node_modules/pm2/bin/pm2 /etc/nginx/pm2.config.js
ExecStop=/usr/local/lib/node_modules/pm2/bin/pm2 kill
導入環境によってはモジュールパスが /usr/local/lib ではなく、/usr/lib の場合もあります。
現在のnpmのプレフィックスを確認します。
$ npm config get prefix
/usr
npmのプレフィックスを/usr/localに変更したい場合は
$ sudo npm config set prefix /usr/local
リブートして、PM2サービスを起動します。
$ sudo reboot
$ sudo systemctl start pm2
実行状態を確認します。
$ sudo systemctl status pm2
● pm2.service - PM2 process manager
Loaded: loaded (/etc/systemd/system/pm2.service; enabled; preset: enabled)
Active: activating (start) since Thu 2026-10-08 12:10:12 JST; 2s ago
Job: 12260
Invocation: 9b2d212827c14d80a70a824a3f01c21b
Docs: https://pm2.keymetrics.io/
Cntrl PID: 3449 (node)
Tasks: 14 (limit: 806)
CPU: 2.792s
CGroup: /system.slice/pm2.service
tq3449 node /usr/lib/node_modules/pm2/bin/pm2 /etc/nginx/pm2.config.js
mq3456 /usr/bin/node /usr/lib/node_modules/pm2/lib/Daemon.js
Oct 08 12:10:12 ns.example.com systemd[1]: pm2.service: Scheduled restart job, restart counter is at 95.
Oct 08 12:10:12 ns.example.com systemd[1]: Starting pm2.service - PM2 process manager...
Oct 08 12:10:14 ns.example.com pm2[3449]: [PM2] Spawning PM2 daemon with pm2_home=/root/.pm2
Raspberry Pi 起動時にサービスが自動実行するように設定します。
$ sudo systemctl enable pm2
Created symlink '/etc/systemd/system/multi-user.target.wants/pm2.service' → '/etc/systemd/system/pm2.service'.
●参考文献
・pm2でNode.js実行環境を整備する
|