GitHub から本番公開まで:Next.js、PostgreSQL、カスタムドメインのデプロイ

Zenavo を使って Next.js アプリと PostgreSQL を自分のサーバーにデプロイし、プライベートネットワーク接続、ビルド時と実行時の環境変数、Prisma マイグレーション、HTTPS ドメイン、自動デプロイを設定します。

この記事は English、简体中文、繁體中文、Español、Bahasa Indonesia でもお読みいただけます。

ローカルで動いている Next.js アプリを本番公開するには、起動スクリプト、データベース接続、環境変数(ビルド時と実行時の違い)、データベースマイグレーション、HTTPS ドメインの5つを順番に整えます。

この記事では、既存の Next.js リポジトリを PostgreSQL と一緒に自分のサーバーで動かす手順を説明します。始める前に、Zenavo に Linux サーバーを接続しておいてください。

1. リポジトリの package.json を確認する

リポジトリに独自の Dockerfile がない場合、Zenavo は zbpack で Next.js を自動認識してビルドします。ロックファイル(package-lock.json、pnpm-lock.yaml、yarn.lock、bun.lockb のいずれか)がコミットされていること、そして package.json に本番用のスクリプトがあることを確認します。

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "engines": {
    "node": ">=20"
  }
}

デプロイ前に一度ローカルで npm run build を実行し、TypeScript の型エラーやビルド時のエラーを先に解消しておきます。

2. PostgreSQL をデプロイする

Zenavo でプロジェクトを作成してサーバーを選び、サービスを追加 → データベース → PostgreSQL をクリックしてバージョンを選び、デプロイします。

データベースはプロジェクト内のプライベートネットワークで動き、初期設定では外部インターネットにポートを公開しません。起動すると同じプロジェクト内のサービスに接続用の変数を共有します。サービス名が postgresql の場合、接続文字列の変数名は POSTGRESQL_CONNECTION_STRING です。

3. GitHub から Next.js アプリを追加する

同じプロジェクトで サービスを追加 → GitHub をクリックし、Zenavo GitHub App にリポジトリの読み取りを許可して、リポジトリ、ブランチ、ルートディレクトリを選択します(モノレポでアプリが apps/web にある場合は、ルートディレクトリに apps/web を指定します)。

環境変数で先ほどのデータベースを参照します。

DATABASE_URL=${POSTGRESQL_CONNECTION_STRING}

${POSTGRESQL_CONNECTION_STRING} は Zenavo のサービス間変数参照で、実行時に実際の内部接続文字列に展開されます(データベースのサービス名を変更した場合は、画面に表示される変数名を使ってください)。

標準の next start はプラットフォームから渡される PORT 環境変数を自動で読み取ります。独自の Dockerfile やカスタムサーバーを使う場合は、0.0.0.0 でリッスンし、Zenavo のサービスに設定した HTTP ポートと一致させてください。詳しくは Next.js デプロイガイドをご覧ください。

4. NEXT_PUBLIC_* とサーバー専用変数の違い

Next.js の環境変数は、次の2種類で挙動が大きく異なります。

  • サーバー専用変数(DATABASE_URL、決済シークレット、AI API キーなど):サーバー側のコードでのみ読み取り、NEXT_PUBLIC_ プレフィックスは付けません。Zenavo の 変数 タブで変更したあとは、サービスを再起動するだけで反映されます。
  • NEXT_PUBLIC_* 変数:next build の実行時にブラウザ向けの JS バンドルへ直接埋め込まれます。NEXT_PUBLIC_* を変更したあとは再デプロイ(再ビルド)が必要で、コンテナを再起動しただけではブラウザ側の値は変わりません。

また、Zenavo のビルド環境は、ビルド中にあなたのサーバー内のプライベートデータベースへ接続できません。そのため:

  • next build の中で本番データベースへ接続する処理を実行しないでください。
  • データベースを読み取るページは、ビルド時の静的生成ではなくリクエスト時の動的レンダリングにしてください。

5. 起動時にデータベースマイグレーションを実行する(Prisma の例)

ビルド中には内部データベースへ接続できないため、テーブルのマイグレーションは build スクリプトではなくコンテナの起動直前に実行します。

zbpack でビルドする場合は、package.json に predeploy スクリプトを追加すると、コンテナ起動時の start の直前に自動実行されます。

{
  "scripts": {
    "build": "prisma generate && next build",
    "predeploy": "prisma migrate deploy",
    "start": "next start"
  }
}

注意点:

  • 本番環境ではコミット済みのマイグレーションだけを適用する prisma migrate deploy を使い、開発用の prisma migrate dev や db push --force-reset は使わないでください。
  • 独自の Dockerfile を使う場合は zbpack の predeploy は呼ばれないため、CMD や ENTRYPOINT で npx prisma migrate deploy && npm start を実行してください。

6. ドメインの設定と自動デプロイ

アプリが起動したら、サービスの ネットワーク タブでドメイン(例:app.example.com)を割り当て、DNS の A レコードをサーバーの IP に向けて、HTTPS 証明書が自動発行されるのを待ちます(詳しくはドメインと HTTPS をご覧ください)。NextAuth / Auth.js、Clerk、OAuth ログインを使っている場合は、NEXTAUTH_URL などの URL 変数や外部プロバイダー側のコールバック URL も忘れずに更新してください。

ページを開いてログインし、テストデータの作成・読み取り・更新・削除を一通り試して、PostgreSQL への読み書きを確認します。

サービスの 設定 で このブランチへのプッシュ時に自動デプロイ をオンにすると、以降は git push のたびにビルドとゼロダウンタイムのロールアウトが行われます。モノレポの場合は監視パスを指定して、対象ディレクトリに変更があったときだけビルドさせることもできます(GitHub からのデプロイを参照)。

よくある質問

ビルドログに Can't reach database server at postgresql.zenavo.internal:5432 と出ます build スクリプトまたは静的生成(SSG)ページが、ビルド時に内部データベースへ接続しようとしています。マイグレーションを predeploy または起動コマンドに移し、データベースを読むページには export const dynamic = 'force-dynamic' を追加してください。

NEXT_PUBLIC_API_URL を変更して再起動したのに、古い URL のままです NEXT_PUBLIC_* はビルド時にフロントエンドのコードへ埋め込まれます。再デプロイ(Redeploy) をクリックしてビルドし直してください。

新しいデプロイに問題があった場合、どうやって戻しますか? デプロイ履歴からワンクリックで前のイメージにロールバックできます。ただし、サービスのロールバックはアプリのイメージと設定を戻すだけで、データベースは元に戻しません。カラム削除など互換性のないマイグレーションを行う前には、PostgreSQL サービスの バックアップと復元 タブでバックアップを取っておいてください。

リポジトリの準備ができたら、Zenavo コンソールでプロジェクトを作成しましょう。PostgreSQL を立ち上げ、GitHub リポジトリをつないで DATABASE_URL とドメインを設定すれば、数分で git push から本番公開までの流れが整います。