📜

【Next.js】Next.jsを使ったカスタムドメインによるマルチテナントアプリの構築方法

2022/01/23に公開

Next.jsを使ったカスタムドメインによるマルチテナントアプリの構築方法

Next.js、Prisma、PlanetScale、Tailwind CSSを使用して、マルチテナントおよびカスタムドメインに対応したフルスタックアプリケーションを作成します。

この記事は以下のサイトの日本語訳になります。英語が苦手の方向けに、和訳をしてみました。

https://vercel.com/guides/nextjs-multi-tenant-application#1.-set-up-your-next.js-project

このガイドでは、Platforms Starter Kitと以下の技術を使用して、フルスタックのマルチテナントアプリケーションを構築する方法を学習します。

  • ReactフレームワークであるNext.js
  • CSSスタイリングのためのTailwind
  • データベースアクセス用ORMとしてPrismaを使用します。
  • データベースはPlanetScale(MySQL)
  • 認証にNextAuth.jsを使用
  • デプロイメント用Vercel

既にプロジェクトがあり、マルチテナンシーの手順だけを見たい場合は、手順4と5まで読み飛ばしてください。また、このアプリのコードはこちらでご覧いただけます。

1. Next.jsプロジェクトのセットアップ

今回は、Platforms Starter Kitを使って、Next.jsのプロジェクトをスタートさせます。
まず、ターミナルを開いて、次のように移動して実行します。

npx create-next-app --example https://github.com/vercel/platforms/tree/main platforms

これで、カレントディレクトリにplatformsという新しいフォルダが作成されます。そして、そのフォルダーに移動して、アプリを起動することができます。

cd platforms && npm run dev

新しいアプリケーションは、以下のような構成になっています。

pages
└───api
└───app
│   │   index.tsx
│   │   login.tsx
│   │   settings.tsx
│   │
│   └───post
│   │   │   ...
│   │
│   └───site
│       │   ...
│
└───home
│   │   index.tsx
│
└───_sites
│       │
│       [site]
│       │   │   index.tsx
│       │   │   [slug].tsx

/pagesディレクトリには、/apiフォルダの他に、主に3つのフォルダがあります。

  • /app: アプリのサブドメイン(app.example.com)用のすべてのルートで、ユーザーが個々のコンテンツページをカスタマイズできるようになっています。
  • /home: ランディングページ(example.com)用の全ルートです。
  • /sites: すべてのユーザーコンテンツページのすべてのルート(例:john.example.comkate.example.com)です。
    これらのフォルダーには、マルチテナントアプリの基本的なアプリ構造が含まれています。ただし、今のところ、/homeルートだけが機能します。続けて、データベースを追加します。

2. MySQLデータベースのセットアップ

  1. 前提条件としてPrismaPlanetScaleのCLIがインストールされている必要があります。
  2. PlanetScaleで新しいアカウントを作成します。
  3. PlanetScale内部で、platformsという新しいデータベースを作成します。
  4. データベースの「設定」ページで、「移行データを自動的にコピーする」にチェックを入れ、「Prisma」を選択します。
  5. データベースのブランチページで、mainブランチからstagingshadowデータベースのブランチを作成します。
  6. 次に、pscaleCLIを使用してPlanetScaleデータベースにローカルでプロキシします。2つの異なるターミナルタブで、実行します。
pscale connect platforms staging --port 3309
pscale connect platforms shadow --port 3310
  1. 別のターミナル・ウィンドウで、Prisma migrateを使用してリモートPlanetScaleデータベース内に必要なテーブルを自動的に作成します。
npx prisma migrate dev --name init

prisma/migrationsフォルダが作成され、PlanetScaleのstagingブランチにスキーマが作成されたことに気づくでしょう。

  1. これで、データベースのプロビジョニングが完了しました。app.localhost:3000にアクセスすると、以下のような画面が表示されるはずです。

  1. スキーマの変更を本番データベースに反映させるには、以下を実行します。
pscale deploy-request create platforms staging
  1. stagingデータベースに接続したターミナルで、代わりに本番データベースに接続し、本番データにアクセスします。
pscale connect platforms main --port 3309

3. next-authでユーザー認証の設定

では、ユーザーがアカウントを作成し、新しいサイトを追加し、カスタムドメインを追加できるように、認証を追加してみましょう。

ここではnext-authライブラリを使用します。この例では、Twitter OAuthを使用するようにあらかじめ設定されています。すべてのユーザデータは、定義されたPrismaスキーマに基づいて、PlanetScaleデータベースに保存されます。

認証のためにTwitterをセットアップする方法は以下となります。

  1. Twitter Developer Portalにアクセスします(以前に開発者アカウントを作成したことがない場合、Twitterでプロジェクト/アプリの作成を開始する前に、Twitter APIアクセスを申請する必要がある場合があります)。
  2. 「Create Project」をクリックします。
  3. プロジェクトに名前を付け、ユースケースを選択し、プロジェクトの性質を説明します。
  4. 次の画面で「Create A New App」を選択します。
  5. アプリの名前を決めて、「次へ」をクリックします。以下のように表示されるはずです。

  1. API Keyをコピーして、.envファイルのTWITTER_IDの下に貼り付けてください。
  2. API Secret Keyをコピーして、.envファイルのTWITTER_SECRETの値の下に貼り付けてください。
  3. API Secret Keyをコピーして、.envファイルのTWITTER_AUTH_TOKENの値の下に貼り付けてください。
  4. 「App settings」をクリックし、新しく作成したTwitterアプリの設定ページに移動します。
  5. 「Authentication settings」までスクロールすると、「3-legged OAuth is disabled」という文字が表示されるはずです。これを有効にしたいのです。「Edit」をクリックします。
  6. これで以下のように表示されるはずです。

  1. 「Enable 3-legged OAuth」オプションをtrueに切り替えます。サインアップ時にユーザーからメールアドレスを収集するかどうかによって、次のオプションもtrueに切り替えたい場合がありますが、その場合、アプリのプライバシーポリシーと利用規約のページのURLを提供する必要があります。

  2. コールバックURLとして、以下のURLを追加します。

    1. http://localhost:3000/api/auth/callback/twitter
    2. https://app.yourdomain.com/api/auth/callback/twitteryourdomain.comは、実運用で使用している実際のドメインに置き換えてください。

これで完了です。これで、アプリのログインページに戻り、Twitterでログインできるようになりました。

4. マルチテナンシー用のリライトの設定

Vercel Edge Functionsは、静的な利点と動的なパワーを提供します。このテンプレートでは、Middlewareを使用して柔軟な書き換えルールを作成します。

まず、/pagesフォルダのルートにある_middleware.jsファイルに移動します。このファイルの中で、各サブドメイン/カスタムドメインと/pages内のダイナミックルートをマッピングするリライトルールを設定しました。

リライトを正しく設定するには、vercel.pubのインスタンスをすべて独自ドメインに置き換える必要があります。

5. Vercelへのデプロイ

次に、このリポジトリをVercelにデプロイします。次のステップでカスタムドメインを追加する機能を設定する必要があるため、これは最終ステップではないことに注意してください。

まず、新しいGithubリポジトリを作成し、ローカルでの変更をプッシュします。
それをVercelにデプロイします。インポート時に.envファイルにあるすべての環境変数をVercelに追加していることを確認します。

6. Vercel APIでカスタムドメインの追加

Vercel APIを使用して、プロジェクトにカスタムドメインを追加し、ユーザーのアカウントに割り当てます。

  1. Vercel Accounts SettingsページのTokensからAUTH_BEARER_TOKENを取得します。その値を.envファイルのAUTH_BEARER_TOKENキーの下に追加します。
  2. https://vercel.com/<TEAM_OR_USER_NAME>/<PROJECT_SLUG>/settingsからあなたのプロジェクトのVERCEL_PROJECT_IDを取得します。
  3. チームアカウントでプロジェクトをデプロイしている場合、VERCEL_TEAM_IDも取得する必要があります。これはhttps://vercel.com/teams/<TEAM_SLUG>/settingsで確認することができます。
  4. カスタムドメインを扱うために、いくつかのAPIルートを設定しました。
    1. /api/add-domain: ユーザーがあなたのプラットフォーム上でドメインを追加するたびに、このエンドポイントを使用してVercelプロジェクトにドメインを追加します。これは、3つの可能な結果を返します。
      1. ステータスコード403: ドメインはすでに他のチームによって所有されていますが、そのチームからの委任を要求して追加することは可能です。
      2. ステータスコード409: そのドメインはすでに別のプロジェクトで使用されています。そのドメインがプロジェクトから削除されない限り、追加することはできません。
      3. ステータスコード200: ドメインは正常に追加されました。
    2. /api/check-domain: プロジェクトにドメインが正常に設定されたかどうかをチェックします。2つの可能な値を返します。
      1. true: ドメインが正常に設定された。
      2. false: ドメインが正しく設定されていない。
    3. /api/request-delegation: ドメインが他のチームに所有されている場合、このエンドポイントを使用して、そのチームからの委任を要求し、追加することができます。
      警告: 我々は積極的にドメイン委任プロセスの改善に取り組んでおり、将来的にこのエンドポイントの必要性はなくなる可能性が高いです。
    4. /api/remove-domain: ユーザーがあなたのプラットフォームからドメインを削除するたびに、このエンドポイントを使用してVercelプロジェクトからのドメインを削除します。

7. 追加機能

Vercelでプラットフォームを構築するために必要と思われる補足的なコードスニペットを以下に示します。

静的ツイート

静的ツイート実装(画像、ビデオ、GIF、投票、リツイート、引用リツイートなどをサポート)を使って、ネイティブTwitter埋め込みによる累積レイアウトシフト(CLS)を回避できます。

Cloudinaryを使った画像アップロード

画像アップロードの処理にCloudinaryを使用しました。以下は、作成した再利用可能なコンポーネントと、アップロードされた画像からブラーハッシュを生成するために使用したコードです。

結論

このガイドでは、Platforms Starter Kitを使用して、フルスタックのマルチテナントアプリケーションを構築する方法を学びました。ブログプラットフォームからローコードツールまで、このスターターキットは様々な種類のアプリケーションのスターターキットとなり得ます。あなたが何を構築するか楽しみですね。

このガイドについて何か問題が発生したり、質問がある場合は、GitHubで提起するか、Next.js Discordに投げかけてください。

Discussion