💡 Tips

XServer VPSでNginxリバースプロキシ+TypeScript Node.jsを本番公開する手順【2025年版】

結論:VPS公開は「PM2で常駐」→「Nginxで443を受ける」の2層に分ければ迷わない

XServer VPSでTypeScript製のNode.jsアプリを本番公開するとき、詰まる原因のほとんどは構成の役割分担が曖昧なことにある。整理すると、やることは次の2層だけだ。

  1. アプリ層:TypeScriptをビルドし、PM2でlocalhost:3000に常駐させる(外部には出さない)
  2. 公開層:Nginxが80/443を受け取り、localhost:3000へリバースプロキシする。SSLはCertbotで自動取得・自動更新

この分離ができていれば、アプリのデプロイとTLS・ドメイン周りを独立して触れる。以下、Ubuntu 24.04 LTSを前提にコマンドまで通しで書く。OSイメージやプラン仕様は変更されることがあるため、契約前に{{A8:xserverVps}}の公式ページで最新のスペックと料金を確認してほしい。

なぜCloudflare WorkersやVercelではなくVPSなのか

正直に書くと、静的サイトや軽いAPIならサーバーレスのほうが楽で安い。VPSを選ぶ理由は次のようなケースに限られる。

要件VPSサーバーレス(Workers等)
常駐プロセス・WebSocket長時間接続得意制約あり
実行時間の長いバッチ・cron自由タイムアウト制限あり
ffmpeg等のネイティブバイナリ利用自由ほぼ不可
OS・ミドルウェアの運用負荷自分持ちほぼゼロ
コスト予測固定従量(跳ねる可能性)

つまり「常駐・長時間処理・ネイティブ依存」がある場合にVPSが効く。逆にそれらが不要なら、Cloudflare Workersでできることを先に検討したほうが運用は圧倒的に楽だ。VPSはOSアップデートもセキュリティパッチも自分の責任になる、というデメリットは最初に飲み込んでおきたい。

Step 1:初期セットアップとファイアウォール

XServer VPSはコンソール側にもパケットフィルターがある。OS内のufwとVPS側フィルターの両方で80/443/22を許可しないと疎通しない。ここが初回の定番の詰まりどころだ。

# 一般ユーザー作成(rootで直接運用しない)
adduser deploy
usermod -aG sudo deploy

# ufw設定
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status

SSHは公開鍵認証に切り替え、/etc/ssh/sshd_configでPasswordAuthentication noにしておく。VPSは公開IPを持つため、放置すると総当たり攻撃のログがすぐ溜まる。

Step 2:Node.jsとPM2の導入

ディストリのaptに入るNodeはバージョンが古いことが多い。nvmでLTSを入れるのが無難だ。

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
source ~/.bashrc
nvm install --lts
node -v

npm install -g pm2

Step 3:TypeScriptアプリをビルドして常駐させる

本番でts-nodeを使うのは避ける。起動が遅く、型チェックの失敗が実行時まで持ち越される。ビルド済みJSを実行するのが原則だ。

{
  "scripts": {
    "build": "tsc -p tsconfig.json",
    "start": "node dist/index.js"
  }
}

アプリ側は必ず127.0.0.1にバインドする。0.0.0.0だとNginxを迂回してポート3000に直接アクセスされうる。

import express from "express";

const app = express();
app.get("/health", (_req, res) => res.json({ ok: true }));

app.listen(3000, "127.0.0.1", () => {
  console.log("listening on 127.0.0.1:3000");
});

PM2の設定はJSONやecosystemファイルで管理し、環境変数もここに寄せる。

npm run build
pm2 start dist/index.js --name myapp --time
pm2 save
pm2 startup systemd   # 出力されたコマンドをsudoで実行

pm2 startupで表示されたコマンドを実行し忘れると、サーバー再起動後にアプリが上がらない。ここは実際にVPSをsudo rebootして復帰を確認しておくべきポイントだ。

Step 4:Nginxのリバースプロキシ設定

/etc/nginx/sites-available/myapp.confを作る。

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;

        # WebSocket用
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "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;

        proxy_read_timeout 60s;
    }
}
sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

X-Forwarded-Protoを渡さないと、Expressでreq.protocolが常にhttpになり、リダイレクトループやCookieのSecure属性の判定を誤る。Express側ではapp.set("trust proxy", 1)を入れておく。この「プロキシ配下でホスト・プロトコルを正しく認識させる」問題は、エッジ環境でも同種の罠がある。認証まわりで踏みやすい例はAuth.js (NextAuth v5) のtrustHost設定の記事も参考になる。

Step 5:Let’s EncryptでSSLを自動取得する

DNSのAレコードをVPSのIPに向け、伝播を確認してからCertbotを実行する。DNSが未反映のまま叩くと認証に失敗し、短時間のリトライ制限に引っかかるので順番は守りたい。

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com

# 自動更新のドライラン
sudo certbot renew --dry-run

--nginxプラグインは設定ファイルへの443ブロック追記とHTTPリダイレクトまで自動で書き換えてくれる。更新はsystemd timerで回るため、cron登録は基本的に不要だ。

運用で効く3つの設定

  • ログローテーション:pm2 install pm2-logrotate。入れないと~/.pm2/logsが肥大してディスクを食う
  • メモリ上限:pm2 start dist/index.js --max-memory-restart 300Mでリークによる巻き込み停止を防ぐ
  • ヘルスチェック:/healthを用意し、外形監視サービスから叩く。プロセスが生きていてもイベントループが詰まる障害は検知できない

ゼロダウンタイム更新が必要ならpm2 reload myappを使う。ただし完全な無停止にはアプリ側でgraceful shutdown(SIGINT受信時に接続を閉じる処理)の実装が要る。

Linuxサーバー運用の土台を体系的に固めたいなら、

Linuxサーバー構築標準教科書 Ubuntu版 Ver.1.0.0: LinuC(リナック)学習にも役立つ (LPI-Japan標準教科書シリーズ)
📚 おすすめ書籍

Linuxサーバー構築標準教科書 Ubuntu版 Ver.1.0.0: LinuC(リナック)学習にも役立つ (LPI-Japan標準教科書シリーズ)

参考価格¥300(税込)

パーミッション・systemd・ログ運用の基礎を通しで押さえられる

Amazonで最新価格をチェック

のような一冊を手元に置いておくと、トラブル時の切り分けが速くなる。

注意点:VPSは「作って終わり」ではない

最後に正直な話をしておく。この構成は動き出せば安定するが、継続的な手入れが必要だ。

  • sudo apt update && sudo apt upgradeとカーネル更新に伴う再起動
  • Node.jsのLTSサポート終了に合わせたバージョン移行
  • バックアップ(スナップショット機能の有無・料金は公式の最新情報を確認)
  • 攻撃トラフィックへの対処(fail2ban導入やNginxのrate limit)

これらを見積もった上で、それでも常駐プロセスやネイティブ依存が必要ならVPSは良い選択になる。まずは検証環境として1台立て、/healthが443越しに200を返すところまでを1本通してみるのが理解の近道だ。