コンテンツにスキップ
App Routerガイドセルフホスティング

Next.js アプリケーションをセルフホストする方法

Next.js アプリケーションをデプロイする際、インフラストラクチャに応じてさまざまな機能の処理方法を設定したい場合があります。

🎥 視聴: Next.js のセルフホスティングについてさらに詳しく → YouTube (45分)

画像最適化

画像最適化next/image を使用して、next start でデプロイする場合、ゼロコンフィグレーションでセルフホストで動作します。画像を最適化する別のサービスが必要な場合は、画像ローダーを設定できます。

画像最適化は、next.config.js でカスタム画像ローダーを定義することにより、静的エクスポートとともに使用できます。画像はビルド時ではなく、実行時に最適化されることに注意してください。

知っておくと良いこと

  • glibc ベースの Linux システムでは、画像最適化で過剰なメモリ使用量を防ぐために追加の設定が必要になる場合があります。
  • 最適化された画像のキャッシュ動作とTTLの設定方法についてさらに詳しく学んでください。
  • また、画像を自分で別途最適化している場合など、next/image を使用する他の利点を維持したまま、画像最適化を無効にすることもできます。

プロキシ

Proxynext start でデプロイする場合、ゼロコンフィグレーションでセルフホストで動作します。着信リクエストへのアクセスが必要なため、静的エクスポートではサポートされていません。

Proxy は、低レイテンシーを保証するために、アプリケーションのすべてのルートまたはアセットの前に実行される可能性がある Node.js API のサブセットであるEdge ランタイムを使用します。これが必要ない場合は、Proxy を実行するために完全な Node.js ランタイムを使用できます。

すべての Node.js API を必要とするロジックを追加したり(または外部パッケージを使用したり)したい場合は、このロジックをレイアウトサーバーコンポーネントに移動できる場合があります。たとえば、ヘッダーをチェックしてリダイレクトするなどです。ヘッダー、Cookie、またはクエリパラメータを使用して、next.config.jsリダイレクトまたは書き換えすることもできます。それでもうまくいかない場合は、カスタムサーバーを使用することもできます。

環境変数

Next.js は、ビルド時と実行時の両方の環境変数をサポートできます。

デフォルトでは、環境変数はサーバーでのみ利用可能です。ブラウザに環境変数を公開するには、NEXT_PUBLIC_ でプレフィックスを付ける必要があります。ただし、これらの公開環境変数は、next build 中に JavaScript バンドルにインライン化されます。

動的レンダリング中にサーバーで環境変数を安全に読み取ることができます。

app/page.ts
import { connection } from 'next/server'
 
export default async function Component() {
  await connection()
  // cookies, headers, and other Dynamic APIs
  // will also opt into dynamic rendering, meaning
  // this env variable is evaluated at runtime
  const value = process.env.MY_VALUE
  // ...
}

これにより、複数の環境を異なる値で昇格できる単一の Docker イメージを使用できます。

知っておくと良いこと

  • register 関数を使用して、サーバー起動時にコードを実行できます。

キャッシュとISR

Next.js は、レスポンス、生成された静的ページ、ビルド出力、および画像、フォント、スクリプトなどのその他の静的アセットをキャッシュできます。

ページ(Incremental Static Regeneration を使用)のキャッシュと再検証には、同じ共有キャッシュが使用されます。デフォルトでは、このキャッシュは Next.js サーバーのファイルシステム(ディスク)に保存されます。これは、Pages Router と App Router の両方を使用してセルフホスティングする場合に自動的に機能します。

キャッシュされたページやデータを耐久性のあるストレージに永続化したい場合、または Next.js アプリケーションの複数のコンテナやインスタンス間でキャッシュを共有したい場合に、Next.js のキャッシュ設定を構成できます。

自動キャッシュ

  • Next.js は、真に不変なアセットに対して Cache-Control ヘッダーを public, max-age=31536000, immutable に設定します。これは上書きできません。これらの不変ファイルにはファイル名に SHA-hash が含まれているため、無期限に安全にキャッシュできます。例: ローカル画像。画像については、TTL を設定できます。
  • Incremental Static Regeneration (ISR) は Cache-Control ヘッダーを s-maxage: <getStaticProps で再検証する時間>, stale-while-revalidate に設定します。この再検証時間は、秒単位で getStaticProps 関数で定義されます。revalidate: false を設定すると、デフォルトで 1 年間のキャッシュ期間になります。
  • 動的にレンダリングされたページは、ユーザー固有のデータがキャッシュされないように、Cache-Control ヘッダーを private, no-cache, no-store, max-age=0, must-revalidate に設定します。これは App Router と Pages Router の両方に適用されます。これには Draft Mode も含まれます。

静的アセット

静的アセットを別のドメインまたは CDN でホストしたい場合は、next.config.jsassetPrefix 設定を使用できます。Next.js は JavaScript または CSS ファイルを取得する際にこのアセットプレフィックスを使用します。アセットを別のドメインに分離すると、DNS および TLS の解決に余分な時間がかかるという欠点があります。

assetPrefix についてさらに詳しく.

キャッシュの設定

デフォルトでは、生成されたキャッシュアセットはメモリ(デフォルト 50mb)とディスクに保存されます。Kubernetes のようなコンテナオーケストレーションプラットフォームで Next.js をホスティングしている場合、各ポッドはキャッシュのコピーを持ちます。デフォルトでキャッシュがポッド間で共有されないため、古いデータが表示されるのを防ぐには、Next.js キャッシュを構成してキャッシュハンドラーを提供し、インメモリ キャッシュを無効にすることができます。

セルフホスティング時に ISR/データキャッシュの場所を構成するには、next.config.js ファイルでカスタムハンドラーを構成できます。

next.config.js
module.exports = {
  cacheHandler: require.resolve('./cache-handler.js'),
  cacheMaxMemorySize: 0, // disable default in-memory caching
}

次に、プロジェクトのルートに cache-handler.js を作成します。例:

cache-handler.js
const cache = new Map()
 
module.exports = class CacheHandler {
  constructor(options) {
    this.options = options
  }
 
  async get(key) {
    // This could be stored anywhere, like durable storage
    return cache.get(key)
  }
 
  async set(key, data, ctx) {
    // This could be stored anywhere, like durable storage
    cache.set(key, {
      value: data,
      lastModified: Date.now(),
      tags: ctx.tags,
    })
  }
 
  async revalidateTag(tags) {
    // tags is either a string or an array of strings
    tags = [tags].flat()
    // Iterate over all entries in the cache
    for (let [key, value] of cache) {
      // If the value's tags include the specified tag, delete this entry
      if (value.tags.some((tag) => tags.includes(tag))) {
        cache.delete(key)
      }
    }
  }
 
  // If you want to have temporary in memory cache for a single request that is reset
  // before the next request you can leverage this method
  resetRequestCache() {}
}

カスタムキャッシュハンドラーを使用すると、Next.js アプリケーションをホストするすべてのポッドで一貫性を確保できます。たとえば、キャッシュされた値を Redis や AWS S3 など、どこにでも保存できます。

知っておくと良いこと

  • revalidatePath は、キャッシュタグの便利なレイヤーです。revalidatePath を呼び出すと、指定されたページの特別なデフォルトタグで revalidateTag 関数が呼び出されます。

ビルドキャッシュ

Next.js は next build 中に ID を生成し、提供しているアプリケーションのバージョンを識別します。同じビルドを使用して複数のコンテナを起動する必要があります。

各環境ステージで再ビルドする場合、コンテナ間で一貫したビルド ID を生成する必要があります。next.config.jsgenerateBuildId コマンドを使用します。

next.config.js
module.exports = {
  generateBuildId: async () => {
    // This could be anything, using the latest git hash
    return process.env.GIT_HASH
  },
}

バージョン不整合

Next.js は、バージョン不整合 のほとんどのインスタンスを自動的に緩和し、検出時に新しいアセットを取得するためにアプリケーションを自動的にリロードします。たとえば、deploymentId に不一致がある場合、ページ間の遷移はプリフェッチされた値を使用するのではなく、ハードナビゲーションを実行します。

アプリケーションがリロードされると、ページナビゲーション間で状態が永続化するように設計されていない場合、アプリケーションの状態が失われる可能性があります。たとえば、URL の状態やローカルストレージを使用すると、ページリフレッシュ後に状態が永続化されます。ただし、useState のようなコンポーネントの状態は、このようなナビゲーションで失われます。

ストリーミングと Suspense

Next.js App Router は、セルフホスティング時にストリーミングレスポンスをサポートしています。Nginx または同様のプロキシを使用している場合は、ストリーミングを有効にするためにバッファリングを無効にするように構成する必要があります。

たとえば、Nginx で X-Accel-Bufferingno に設定してバッファリングを無効にできます。

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*{/}?',
        headers: [
          {
            key: 'X-Accel-Buffering',
            value: 'no',
          },
        ],
      },
    ]
  },
}

キャッシュコンポーネント

Cache Components は Next.js でデフォルトで動作し、CDN 専用の機能ではありません。これには、Node.js サーバー(next start 経由)としてのデプロイメント、および Docker コンテナとの使用が含まれます。

CDN との連携

Next.js アプリケーションの前に CDN を使用する場合、動的 API にアクセスすると、ページには Cache-Control: private レスポンスヘッダーが含まれます。これにより、結果の HTML ページがキャッシュ不能としてマークされます。ページが完全に静的にプリレンダリングされる場合、Cache-Control: public が含まれ、CDN でページをキャッシュできるようになります。

静的コンポーネントと動的コンポーネントの混在が必要ない場合は、ルート全体を静的にして、CDN で出力 HTML をキャッシュできます。これは、動的 API が使用されていない場合、next build を実行する際のデフォルトの動作である自動静的最適化です。

Partial Prerendering が安定版に移行するにつれて、Deployment Adapters API を通じてサポートを提供します。

after

after は、next start でセルフホスティングする場合に完全にサポートされています。

サーバーを停止する際は、SIGINT または SIGTERM シグナルを送信し、待機することで、正常なシャットダウンを保証してください。これにより、Next.js サーバーは、after 内で使用される保留中のコールバック関数またはプロミスが完了するまで待機できます。