【Next.js】Next.jsを使ったカスタムドメインによるマルチテナントアプリの構築方法
Next.jsを使ったカスタムドメインによるマルチテナントアプリの構築方法
Next.js、Prisma、PlanetScale、Tailwind CSSを使用して、マルチテナントおよびカスタムドメインに対応したフルスタックアプリケーションを作成します。
この記事は以下のサイトの日本語訳になります。英語が苦手の方向けに、和訳をしてみました。
このガイドでは、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.com
、kate.example.com
)です。
これらのフォルダーには、マルチテナントアプリの基本的なアプリ構造が含まれています。ただし、今のところ、/home
ルートだけが機能します。続けて、データベースを追加します。
2. MySQLデータベースのセットアップ
- 前提条件としてPrismaとPlanetScaleのCLIがインストールされている必要があります。
- PlanetScaleで新しいアカウントを作成します。
- PlanetScale内部で、
platforms
という新しいデータベースを作成します。 - データベースの「設定」ページで、「移行データを自動的にコピーする」にチェックを入れ、「Prisma」を選択します。
- データベースのブランチページで、
main
ブランチからstaging
とshadow
データベースのブランチを作成します。 - 次に、
pscale
CLIを使用してPlanetScaleデータベースにローカルでプロキシします。2つの異なるターミナルタブで、実行します。
pscale connect platforms staging --port 3309
pscale connect platforms shadow --port 3310
- 別のターミナル・ウィンドウで、Prisma migrateを使用してリモートPlanetScaleデータベース内に必要なテーブルを自動的に作成します。
npx prisma migrate dev --name init
prisma/migrations
フォルダが作成され、PlanetScaleのstaging
ブランチにスキーマが作成されたことに気づくでしょう。
- これで、データベースのプロビジョニングが完了しました。app.localhost:3000にアクセスすると、以下のような画面が表示されるはずです。
- スキーマの変更を本番データベースに反映させるには、以下を実行します。
pscale deploy-request create platforms staging
-
staging
データベースに接続したターミナルで、代わりに本番データベースに接続し、本番データにアクセスします。
pscale connect platforms main --port 3309
3. next-authでユーザー認証の設定
では、ユーザーがアカウントを作成し、新しいサイトを追加し、カスタムドメインを追加できるように、認証を追加してみましょう。
ここではnext-auth
ライブラリを使用します。この例では、Twitter OAuthを使用するようにあらかじめ設定されています。すべてのユーザデータは、定義されたPrismaスキーマに基づいて、PlanetScaleデータベースに保存されます。
認証のためにTwitterをセットアップする方法は以下となります。
- Twitter Developer Portalにアクセスします(以前に開発者アカウントを作成したことがない場合、Twitterでプロジェクト/アプリの作成を開始する前に、Twitter APIアクセスを申請する必要がある場合があります)。
- 「Create Project」をクリックします。
- プロジェクトに名前を付け、ユースケースを選択し、プロジェクトの性質を説明します。
- 次の画面で「Create A New App」を選択します。
- アプリの名前を決めて、「次へ」をクリックします。以下のように表示されるはずです。
- API Keyをコピーして、
.env
ファイルのTWITTER_ID
の下に貼り付けてください。 - API Secret Keyをコピーして、
.env
ファイルのTWITTER_SECRET
の値の下に貼り付けてください。 - API Secret Keyをコピーして、
.env
ファイルのTWITTER_AUTH_TOKEN
の値の下に貼り付けてください。 - 「App settings」をクリックし、新しく作成したTwitterアプリの設定ページに移動します。
- 「Authentication settings」までスクロールすると、「3-legged OAuth is disabled」という文字が表示されるはずです。これを有効にしたいのです。「Edit」をクリックします。
- これで以下のように表示されるはずです。
-
「Enable 3-legged OAuth」オプションをtrueに切り替えます。サインアップ時にユーザーからメールアドレスを収集するかどうかによって、次のオプションもtrueに切り替えたい場合がありますが、その場合、アプリのプライバシーポリシーと利用規約のページのURLを提供する必要があります。
-
コールバックURLとして、以下のURLを追加します。
http://localhost:3000/api/auth/callback/twitter
-
https://app.yourdomain.com/api/auth/callback/twitter
yourdomain.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を使用して、プロジェクトにカスタムドメインを追加し、ユーザーのアカウントに割り当てます。
-
Vercel Accounts SettingsページのTokensから
AUTH_BEARER_TOKEN
を取得します。その値を.env
ファイルのAUTH_BEARER_TOKENキー
の下に追加します。 -
https://vercel.com/<TEAM_OR_USER_NAME>/<PROJECT_SLUG>/settings
からあなたのプロジェクトのVERCEL_PROJECT_ID
を取得します。 - チームアカウントでプロジェクトをデプロイしている場合、
VERCEL_TEAM_ID
も取得する必要があります。これはhttps://vercel.com/teams/<TEAM_SLUG>/settings
で確認することができます。 - カスタムドメインを扱うために、いくつかのAPIルートを設定しました。
-
/api/add-domain
: ユーザーがあなたのプラットフォーム上でドメインを追加するたびに、このエンドポイントを使用してVercelプロジェクトにドメインを追加します。これは、3つの可能な結果を返します。- ステータスコード
403
: ドメインはすでに他のチームによって所有されていますが、そのチームからの委任を要求して追加することは可能です。 - ステータスコード
409
: そのドメインはすでに別のプロジェクトで使用されています。そのドメインがプロジェクトから削除されない限り、追加することはできません。 - ステータスコード
200
: ドメインは正常に追加されました。
- ステータスコード
-
/api/check-domain
: プロジェクトにドメインが正常に設定されたかどうかをチェックします。2つの可能な値を返します。-
true
: ドメインが正常に設定された。 -
false
: ドメインが正しく設定されていない。
-
-
/api/request-delegation
: ドメインが他のチームに所有されている場合、このエンドポイントを使用して、そのチームからの委任を要求し、追加することができます。
警告: 我々は積極的にドメイン委任プロセスの改善に取り組んでおり、将来的にこのエンドポイントの必要性はなくなる可能性が高いです。 -
/api/remove-domain
: ユーザーがあなたのプラットフォームからドメインを削除するたびに、このエンドポイントを使用してVercelプロジェクトからのドメインを削除します。
-
7. 追加機能
Vercelでプラットフォームを構築するために必要と思われる補足的なコードスニペットを以下に示します。
静的ツイート
静的ツイート実装(画像、ビデオ、GIF、投票、リツイート、引用リツイートなどをサポート)を使って、ネイティブTwitter埋め込みによる累積レイアウトシフト(CLS)を回避できます。
Cloudinaryを使った画像アップロード
画像アップロードの処理にCloudinaryを使用しました。以下は、作成した再利用可能なコンポーネントと、アップロードされた画像からブラーハッシュを生成するために使用したコードです。
結論
このガイドでは、Platforms Starter Kitを使用して、フルスタックのマルチテナントアプリケーションを構築する方法を学びました。ブログプラットフォームからローコードツールまで、このスターターキットは様々な種類のアプリケーションのスターターキットとなり得ます。あなたが何を構築するか楽しみですね。
このガイドについて何か問題が発生したり、質問がある場合は、GitHubで提起するか、Next.js Discordに投げかけてください。
Discussion