![[自サーバでNext.jsアプリを動かす#1]Node.jsインストール+Nginx設定+デプロイ](/_next/image?url=%2Farticles%2Fnext-js%2Fnginx-setting%2Fhero.jpg&w=3840&q=75)
自サーバでNext.jsアプリを動かす#1Node.jsインストール+Nginx設定+デプロイ
Next.jsで作成したWebサイト・アプリを自サーバのNginxで動かすための設定とデプロイ作業の整理
初回公開日
最終更新日
Next.jsで作成したWebサイトやWebアプリを動作させるサーバといえば、「Vercelサーバ」が最初の選択肢になると思います。Next.js関連の書籍でもそうした内容が多いです。しかし、やはり自社で運用しているサーバにアップして動かしたいという需要もあると思います。
私自身がそうしたかったのですが、初心者のため、なかなか苦労しました。
ここではその実践記録を共有します。
すでにSSLやバーチャルホストの設定は完了済みで、通常のHTMLファイルはNginxでブラウザ表示可能な状態まで完了している前提となります。
サーバ構築については...
今回作業する環境は、下記のとおりです。
- サーバOS:Ubuntu 24.04 LTS
- Webサーバ:Nginx 1.28.0
- ルートディレクトリ:/var/www/example.com/html (example.comが対象ドメインとします)
- バーチャルホスト設定:/etc/nginx/conf.d/example.com.conf()
- SSL:Let's Encrypt(Certbot 4.0.0)で設定済み
- http通信:http/3を設定済み(未対応ブラウザようにhttp2へフォールバック)
- /etc/nginx/nginx.conf にはgzip関連の設定も済み
上記の設定関連については[サーバ構築・運用]-[新規構築]の記事を参照してください。
今回の作業目標は、ビルドされたNext.jsのデフォルトページを表示することです。
1.【サーバ側作業】Node.jsのインストール
Next.jsを動かすにはNode.jsが必要です。なので、まずはNode.jsをサーバへインストールします。
Ubuntu 24.04の標準リポジトリでインストール可能なNode.js
のバージョンを調べる
bash
1sudo apt update
2apt-cache policy nodejs
bash
1nodejs:
2 インストールされているバージョン: (なし)
3 候補: 18.19.1+dfsg-6ubuntu5
4 バージョンテーブル:
5 18.19.1+dfsg-6ubuntu5 500
6 500 http://archive.ubuntu.com/ubuntu noble/universe amd64 Packages
標準リポジトリからのインストールだと
nodejs-18.19.1
がインストールされるようです。
2025年3月25日現在は、Node.js安定版(LTS)の最新はnodejs-22.14.0
となっています。
https://nodejs.org/ja/blog/release 最新の安定版をイントールしていきます。
Node.js公式リポジトリのGPGキーをバイナリ形式で保存
Ubuntu標準リポジトリ以外からインストールを行うには、バイナリ形式(.gpg)でGPGキーを保存 するのが推奨されています。
bash
1sudo mkdir -p /etc/apt/keyrings #/etc/apt/keyringsディレクトリがない場合
2curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | \
3 sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
- curl -fsSL → Node.js公式のGPGキーを取得
- gpg --dearmor -o /etc/apt/keyrings/nginx.gpg → バイナリ形式(.gpg)に変換して保存
Node.js公式リポジトリを追加
次に、Node.js v22.x のAPTリポジトリを追加します。
bash
1echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" | \
2 sudo tee /etc/apt/sources.list.d/nodesource.list > /dev/null
- signed-by=/etc/apt/keyrings/nginx.gpg → GPGキーの正しいパスを指定
- nodistro は Ubuntu 24.04(noble)がまだ正式サポート外なので、NodeSourceが推奨する記述
パッケージリストを更新して、Node.js のインストール
bash
1sudo apt update
2sudo apt install nodejs -y
バージョンの確認
bash
1node -v
2v22.16.0
3
4npm -v
510.9.2
と
v22.16.0
が表示されれば成功です。npmをバージョンアップ
npmは2025年5月27日現在、最新安定版は11.4.Xになっています。npmを最新版へアップデートしておきます。
bash
1sudo npm install -g npm@latest
バージョンの確認
bash
1npm -v
211.4.1
- npmの更新についてはNode.jsをaptで管理するようにしたため、
apt update
でnode.js
が更新されるとnpmのバージョンがNode.js公式リボジトリで管理されるものへダウングレードされることがあります。nodeとnpmはnvm
で管理する方が良いかもしれません。これは別途記事にしたいと思います。
以上で、インストールは完了です。
2.【サーバ側作業】NginxのNext.js用の基本設定
Nginxの設定ですが、一旦、キャッシュとセキュリティヘッダの設定は省略して、動作可能な状態を目指します。
まず、NginxとNext.jsの関係を把握しておきます。
Nginxは「リバースプロキシ」として使います。Nginxがユーザーからのリクエストを受け取り、バックエンド(今回はNext.js)へ中継し、そのレスポンスをユーザーへ返す動作を担ってもらいます。
- クライアント(ブラウザ)は
https://example.com
にアクセス - そのアクセスは Nginxが受け取る
- Nginxはそのリクエストを Next.js(Node.js)で動くバックエンドへ転送(例:
http://localhost:3000
) - Next.jsがレスポンスを返すと、それをNginxがクライアントに返す
「中継者としてNginxに働いてもらう」動作がリバースプロキシの動作ということになります。Next.jsやNode.jsはWebサーバの役割はありませんので、このような中継機能の担い手が必要になるわけです。
/etc/nginx/conf.d/example.com.conf への追記
まず、現状(対象のserverブロックだけ):
bash : example.com.conf
1server {
2 listen 443 ssl default_server;
3 listen [::]:443 ssl default_server;
4 http2 on;
5 listen 443 quic reuseport;
6 listen [::]:443 quic reuseport;
7
8 server_name example.com;
9
10 # HTTP/3 をサポートすることを通知(Alt-Svc ヘッダー)
11 add_header Alt-Svc 'h3=":443"; ma=86400' always;
12
13 # Basic認証
14 auth_basic "Restricted Area"; # <-認証プロンプトのタイトル
15 auth_basic_user_file /etc/nginx/.htpasswd; # <-認証ファイルのパス
16 ##
17
18 root /var/www/example.com/html;
19 index index.html;
20
21 location / {
22 try_files $uri $uri/ =404;
23 }
24
25 ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
26 ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
27 include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
28 ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
29
30}
上記へ変更・追記していきます。
diff : example.com.conf
1server {
2・・上部省略・・
3
4 root /var/www/example.com/html;
5- index index.html;
6
7- location / {
8- try_files $uri $uri/ =404;
9- }
10
11+ # Next.js用のアクセス禁止
12+ # セキュリティ:特定ファイルのアクセス禁止
13+ location ~* /(package(-lock)?\.json|next\.config\.(js|ts)|\.env.*) {
14+ deny all;
15+ }
16
17+ # セキュリティ:prisma ディレクトリのアクセス禁止
18+ location ^~ /prisma/ {
19+ deny all;
20+ }
21
22+ # セキュリティ:隠しファイルやディレクトリ(.git, .env, .vscode など)
23+ location ~ /\. {
24+ deny all;
25+ }
26
27+ # Next.jsメインルート
28+ location / {
29+ proxy_pass http://localhost:3000;
30+ proxy_http_version 1.1;
31
32+ proxy_set_header Upgrade $http_upgrade;
33+ proxy_set_header Connection 'upgrade';
34+ proxy_set_header Host $host;
35+ proxy_set_header X-Real-IP $remote_addr;
36+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
37+ proxy_set_header X-Forwarded-Proto $scheme;
38+
39+ proxy_cache_bypass $http_upgrade;
40+ }
41
42+ # _next/static や image 最適化ルート
43+ location /_next/ {
44+ proxy_pass http://localhost:3000;
45+ proxy_http_version 1.1;
46+ proxy_set_header Host $host;
47+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
48+ }
49
50・・下部省略・・
51}
それぞれの説明です。
bash
1# セキュリティ:特定ファイルのアクセス禁止
2location ~* /(package(-lock)?\.json|next\.config\.(js|ts)|\.env.*) {
3 deny all;
4}
5
6# セキュリティ:prisma ディレクトリのアクセス禁止
7location ^~ /prisma/ {
8 deny all;
9}
10
11# セキュリティ:隠しファイルやディレクトリ(.git, .env, .vscode など)
12location ~ /\. {
13 deny all;
14}
↑Next.jsを動作させるためにサーバへアップロードしないといけないファイル(後述)や隠しファイル関連へのアクセスを禁止する。
bash
1location / {
2 proxy_pass http://localhost:3000;
↑Nginxが / へのリクエストを受けたら、localhost:3000(Next.jsアプリ)へ転送。
bash
1proxy_http_version 1.1;
↑HTTP/1.1で通信。
- proxy_http_version は、Nginx(=リバースプロキシ)がバックエンドサーバー(Next.js)にリクエストを送るときのHTTPバージョンを指定するものです。
- Node.jsのhttpモジュールや多くのバックエンドがHTTP/1.1ベース
- HTTP/2やHTTP/3はproxy_passのバックエンド通信に対応してない or 非推奨
- WebSocket対応などのためにも必要。WebSocketはチャットシステムなどの双方向通信を利用するときに使用するプロトコルです。
bash
1proxy_set_header Upgrade $http_upgrade;
2proxy_set_header Connection 'upgrade';
↑WebSocket対応用のヘッダー。Next.jsでSocket系を使うときに必要(不要なら削除しても動くが、保険として残すのが吉)。
bash
1proxy_set_header Host $host;
2proxy_set_header X-Real-IP $remote_addr;
3proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
4proxy_set_header X-Forwarded-Proto $scheme;
↑これらは「リクエスト元の情報(IP・プロトコルなど)」をバックエンドに正しく伝えるためのヘッダ。
bash
1proxy_cache_bypass $http_upgrade;
↑WebSocketなどのアップグレード時にキャッシュをバイパスする設定。
bash
1 location /_next/ {}
↑Next.jsは/_next/image と /_next/static にビルドデータが格納されるので、これらが正しく proxy_pass されていないと、画像が表示されない or 404になるというトラブルになります。通常の / ルートとは別で扱うべきルートなので、Nginxで個別にlocationディレクティブを定義する必要があります。
もし、Next.jsのApp Routerのapiを使う場合は加えて、
/_next/
と同じ内容でlocation /api/ {}
を作成しておいてください。私の環境では基本はサーバアクションで構築するため、api
ディレクティブは設定していません。編集が終わったら、Nginxをリロード
bash
1sudo nginx -t
2sudo systemctl reload nginx
3.【ローカルPC側作業】Next.js作成アプリのアップロード
ビルドは「ローカルで完結」 → サーバは「実行専用」という前提で記述します。
この方が、安全で、余計なファイルをアップせずに済むからです。
私は最初ビルドデータである
.next/
ディレクトリの内容だけアップすればいいのでは? と思っていたのですが、それは間違いです。.next/だけをアップしてはいけない理由
○「.next/」はビルド成果物だけで、依存関係(node_modules)や設定情報が含まれていない
「.next/」はあくまでNext.jsのコンパイル済みアプリでこれを動かすには下記のデータ必要です。
「.next/」はあくまでNext.jsのコンパイル済みアプリでこれを動かすには下記のデータ必要です。
- node_modules/
- package.json
- next.config.ts
- public/(画像・静的ファイル)
これらが揃っていないと本番サーバで正常に動きません。
○Next.jsの実行形式はNode.jsアプリであり、完全自己完結ではない
- .next/だけでは、必要なモジュールや設定ファイルを失っているため、動作しない
- 本番環境で npm run start を叩くには、Next.jsアプリ一式+依存モジュールが必要
○node_modulesは通常アップロードしないが、サーバ側でnpm installを行う必要がある
- node_modules/は巨大なのでアップロード非推奨
- package.json + package-lock.json は必須
- サーバで npm ci などで再インストールするのが正攻法
アップロード必要ファイル
というわけどアップロードが必要なファイルと必要なファイルを分けると下記のとおりです。
text
1必要:
2├── .next/ ← ビルド成果物
3├── public/ ← 静的ファイル
4├── prisma/ ← 使っていれば
5├── package.json
6├── package-lock.json
7├── next.config.ts(使ってるなら)
8
9アップロードしない:
10├── .env系
11├── .ignore系
12├── その他.*系
13├── eslint.config.mjs
14├── tsconfig.json
15├── postcss.config.mjs
16├── next-env.d.ts
17├── node_modules/
18├── src/app/ ← ビルドデータに含まれるから
「.env」の扱いについて補足:本番環境では、.envファイルをアップロードせず、PM2の設定ファイル(ecosystem.config.js)や、環境変数で渡す方法がベスト(後述)。
その他コンパイル時にのみ利用しているファイルなども不要になります。
その他コンパイル時にのみ利用しているファイルなども不要になります。
アップロードコマンド例:
SFTPやSCPなどでアップロードしても良いのですが、ファイル数が多いので私は
rsync
コマンドを利用しています。アップロードが早い印象があります。下記はあくまで例です。「[サーバ構築編#6] UbuntuへNginx1.26.3をインストール」で作業した
SetGID
やsetfacl(ACL)
が済んでいる前提です。これらをやっていない場合は、所有者やパーミッション回りの指定も必要になります(--chown=user:www-data
や--chmod=D2775,F664
)。rsync : sample
1rsync -avz --delete \
2 --exclude='node_modules' \
3 --exclude='src' \
4 --exclude='tsconfig.json' \
5 --exclude='.git/' \
6 --exclude='.vscode/' \
7 --exclude='.env*' \
8 --exclude='postcss.config.*' \
9 --exclude='eslint.config.*' \
10 --exclude='next-env.d.ts' \
11 --exclude='.gitignore' \
12 --exclude='.prettierrc' \
13 --exclude='.DS_Store' \
14 --exclude='components.json' \
15 xxxx/xxxx/project/new-app/ \
16 user@xxx.xxx.xxx.xxx:/var/www/example.com/html/
オプション | 説明 |
---|---|
-a | パーミッション保持・再帰的コピーなどの「アーカイブモード」 |
-v | 実行内容を表示 |
-z | 転送時に圧縮 |
--delete | サーバ側に存在していてローカルにないファイルを削除(完全ミラー) |
--exclude | 指定パターンを除外(複数可) |
-e "ssh -i ... -p ..." | ssh接続の認証ファイルとポート番号 |
/xxxx/xxxx/project/newapp/ | アップ元のローカルPCのディレクトリ |
user@xxx.xxx.xxx.xxx:/var/www/example.com/html/ | ssh接続のユーザ@サーバIP:アップ先のディレクトリ |
もし、macユーザで「[小技:Mac限定]SSH接続時に秘密鍵のパスフレーズ入力が不要に?!」で
~/.ssh/config
でSSHの接続設定をしている方は、下記ように少し省略可能です。zsh
1rsync -avz --delete \
2 --exclude='node_modules' \
3 --exclude='src' \
4 --exclude='tsconfig.json' \
5 --exclude='.git/' \
6 --exclude='.vscode/' \
7 --exclude='.env*' \
8 --exclude='postcss.config.*' \
9 --exclude='eslint.config.*' \
10 --exclude='next-env.d.ts' \
11 --exclude='.gitignore' \
12 --exclude='.prettierrc' \
13 --exclude='.DS_Store' \
14 --exclude='components.json' \
15 -e "ssh" \
16 /xxxx/xxxx/project/new-app/ \
17 my-web-server:/var/www/example.com/html/
--exclude=
が結構長くなるので、より柔軟にしたいなら .rsync-exclude ファイルに分けて管理もできる
zsh : .rsync-exclude
1# .rsync-exclude
2node_modules
3src
4tsconfig.json
5.git/
6.vscode/
7.env*
8postcss.config.*
9eslint.config.*
10next-env.d.ts
11.gitignore
12.prettierrc
13.DS_Store
14components.json
zsh
1rsync -avz --delete --exclude-from='.rsync-exclude' -e "ssh" \
2 ~/project/new-app/ \
3 my-web-server:/var/www/example.com/html/
こんな感じでアップロードを完了させます。
4.【サーバ側作業】依存関係のあるモジュールのインストール
この作業はアップロードが終わったらサーバ側で毎回やる作業になります。
bash
1cd /var/www/example.com/html/
2npm ci
prismaを利用している場合は下記も合わせて実行:
bash
1npx prisma generate
npm install
じゃないの? という方もいると思います。npm ci
とnpm install
は次のような違いがあります。○npm ci と npm install の違い(本番運用で使うべきはどっち?)
コマンド | 用途 | 特徴・ポイント |
---|---|---|
npm install | 開発・普段使い全般 | package.json を見て、package-lock.jsonと整合性がなければ更新してしまう |
npm ci | 本番環境・CI/CD向けのインストール | package-lock.json に完全準拠。超高速・再現性あり。node_modulesがあれば削除して再構築 |
○npm ci が本番向けな理由
- 再現性が100%保証される(lockファイルどおりにインストール)
- 依存のバージョンが勝手に変わらない
- CI/CDパイプラインでも使われる業界標準
5.【サーバ側作業】とりあえずの実行
もし、対象プロジェクトのルートディレクトリから移動していた場合
bash
1cd /var/www/example.com/html/
続いて、フォアグラウンドで、とりあえずのNext.jsアプリの実行
bash
1npm start
とりあえず、これでブラウザでNext.jsのデフォルトページは表示できます。ぜひ、確認してみてください。

確認が終わったら、[control]+[c]でフォアグラウンドをキャンセルしてください。
これで、サーバ上にアップロードしたNext.jsアプリを、手動で起動して確認することができました。
しかし、この方法ではターミナルを閉じるとアプリが停止してしまいます。
本番運用では「再起動後の自動起動」「ログ管理」「複数アプリのプロセス管理」なども必要になってきます。
次回は、それらを簡単に実現できる PM2 を使った運用方法をご紹介します!
続きはこちら...
この記事の執筆・編集担当
DE
松本 孝太郎
DELOGs編集部/中年新米プログラマー
ここ数年はReact&MUIのフロントエンドエンジニアって感じでしたが、Next.jsを学んで少しずつできることが広がりつつあります。その実践記録をできるだけ共有していければと思っています。
▼ 関連記事
[自サーバでNext.jsアプリを動かす#2]PM2を利用して、快適にNext.jsアプリを動かす
Next.jsで作成したWebサイト・アプリを自サーバで運用するために「PM2」というミドルウェアを利用して、快適に運用して方法のまとめ
2025/6/20公開
![[自サーバでNext.jsアプリを動かす#2]PM2を利用して、快適にNext.jsアプリを動かすのイメージ](/_next/image?url=%2Farticles%2Fnext-js%2Fpm2%2Fhero-thumbnail.jpg&w=1200&q=75)
[自サーバでNext.jsアプリを動かす#3]Nginxのキャッシュゾーン設定
キャッシュゾーンを利用してサーバ負荷を軽減しながらNext.jsで構築したWebアプリケーションを運用
2025/6/20公開
![[自サーバでNext.jsアプリを動かす#3]Nginxのキャッシュゾーン設定のイメージ](/_next/image?url=%2Farticles%2Fnext-js%2Fnginx-cache%2Fhero-thumbnail.jpg&w=1200&q=75)
[自サーバでNext.jsアプリを動かす#4]セキュリティヘッダと静的アセットのキャッシュ期間の設定
Next.jsで作成したWebサイト・アプリケーションを自サーバで運用するためのNginxのセキュリティヘッダと静的アセットのキャッシュ期間設定を実施
2025/6/20公開
![[自サーバでNext.jsアプリを動かす#4]セキュリティヘッダと静的アセットのキャッシュ期間の設定のイメージ](/_next/image?url=%2Farticles%2Fnext-js%2Fnginx-header%2Fhero-thumbnail.jpg&w=1200&q=75)
[自サーバでNext.jsアプリを動かす#5]リードレプリカ(スレーブ)DBの利用
SELECT系専用のリードレプリカ(スレーブ)DBとマスタDBへの接続を同居させる方法
2025/6/20公開
![[自サーバでNext.jsアプリを動かす#5]リードレプリカ(スレーブ)DBの利用のイメージ](/_next/image?url=%2Farticles%2Fserver%2Fdb-replica%2Fhero-thumbnail.jpg&w=1200&q=75)