本文へ移動
verified onnext@16.3.5react@19
最終検証日 2026-09-26
Next.js道場

自分のサーバーに置く。standalone と Docker

output を standalone にすると、server.js だけで動く出力ができますが、.next/static と public は入りません。

standalone が出すもの、出さないもの

next.config.ts に output: 'standalone' と書いてビルドすると、.next/standalone ができます。node_modules を丸ごと持っていかなくても、server.js だけで起動できる形です。

中身を実機で確かめました。

.next/standalone の中身(実機で確かめた)
入っているか
server.js / package.json入っている
使っている node_modules だけ入っている
.next(サーバー側の出力)入っている
.next/static(CSS と JavaScript)入っていない
public(画像など)入っていない

公式ドキュメントによると、静的なファイルは本来 CDN から配るものなので、既定では写さない作りです。自分のサーバーだけで配るなら、自分で写します。

写し忘れると、ページは出るのに壊れている

.next/static と public を写さずに server.js を起動しました。

写さずに起動したとき(実機で確かめた)
取りに行ったもの写さない写す
ページの HTML200200
CSS404200
JavaScript404200
public のファイル404200

Dockerfile の形

ビルドする段と、動かす段を分けます。動かす段には standalone と、写す2つだけを置きます。

FROM node:22-alpine AS builder
WORKDIR /app
COPY . .
RUN npm ci && npx next build

FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production PORT=3000 HOSTNAME=0.0.0.0
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
CMD ["node", "server.js"]

写す先は、server.js から見て .next/static と public です。server.js はそこにあるファイルを自分で配ります。

実機で、この Dockerfile のままビルドして動かし、ページも CSS も public のファイルも 200 で返ることを確かめました。そのとき .dockerignore に node_modules と .next を書いて、手元のものがビルドに混ざらないようにしています。

このサイトも、同じ形の Dockerfile で自分のサーバーに置いています。

HOSTNAME を指定しないと、中からつながらない

server.js は、環境変数の PORT(無ければ 3000)と HOSTNAME(無ければ 0.0.0.0)で待ち受け先を決めます。生成された server.js の中身で確かめました。

ところが Docker は、コンテナの中の HOSTNAME に自動でコンテナの ID を入れます。実際に Docker で動かして比べました。

Docker で動かしたとき(実機で確かめた)
外から(ポート経由)コンテナの中から 127.0.0.1
HOSTNAME を指定しない200つながらない
HOSTNAME=0.0.0.0200つながる

指定しないと、起動のログにも http://<コンテナの ID>:3000 と出ます。外からは見えるので、動いているように見えます。困るのは、コンテナの中から localhost に問い合わせるヘルスチェックだけが失敗するときです。

ENV HOSTNAME=0.0.0.0 を書いておけば、どちらからもつながります。

next start ではなく node server.js

standalone にしたまま next start で起動すると、こう警告されます。

⚠ "next start" does not work with "output: standalone" configuration. Use "node .next/standalone/server.js" instead.

実機では、警告を出したうえでページは返りました。動いてしまうので、standalone を使っていないことに気づきにくくなります。本番は node server.js で起動します。

環境変数はビルドのときに決まるものがある

Docker で環境変数を実行時にだけ渡すと、事前に描くページには undefined が焼き付きます。NEXT_PUBLIC_ の付いた変数も、ビルドのときの値で固まります(環境変数はいつ読まれるのか)。

どの値をビルドのときに渡し、どの値を実行時に渡すかを、Dockerfile を書く前に分けてください。

入れ子のリポジトリでは server.js の場所が変わる

実機で、リポジトリの中に入れ子になったプロジェクトをビルドすると、server.js が .next/standalone の直下ではなく、リポジトリの根からの相対位置(.next/standalone/<入れ子のパス>/server.js)に置かれました。

Dockerfile の CMD がそのままでは見つからなくなります。複数のプロジェクトを1つのリポジトリで持っているなら、ビルドしたあと server.js がどこに出たかを一度確かめてください。公式ドキュメントは、追跡の起点を outputFileTracingRoot で指定できるとしています。

出す前の確認

  1. .next/standalone に server.js があるか(入れ子なら場所も)
  2. .next/static と public を写したか
  3. HOSTNAME=0.0.0.0 を渡しているか
  4. ビルドのときに渡すべき環境変数を渡したか
  5. ブラウザで開いて、見た目とボタンが動くか

出典

このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。

理解できたか試す

では、このコードはどうなりますか。

output を standalone にしてビルドし、.next/standalone だけをサーバーへ持っていきました。CSS や JavaScript のファイル(.next/static)は、その中に入っていますか。

この問題を解くこのテーマの問題 3 問