kt-tech.blog

画像

【トラブルシューティング】本番デプロイで遭遇した問題と解決策まとめ

Share
📌
概要: Next.js × Cloudflare Workers の本番環境を初めてデプロイした際に遭遇した問題と、その解決策をまとめました。pgvector拡張の未インストール、NextAuth v5のUntrustedHostエラー、robots.txtの環境別制御など、実践的なトラブルシューティング集です。

はじめに

本番環境を一から構築してデプロイした際、開発環境では発生しなかった様々な問題に遭遇しました。この記事では、それぞれの問題の原因と解決策を記録します。

この記事でわかること

  • Prisma Postgres × pgvectorで新規DBデプロイ時に起きるエラーの対処法

  • NextAuth v5のCloudflare Workers環境でのUntrustedHostエラーの解決

  • Stripe環境変数未設定時のビルドエラーへの対処

  • robots.txt / noindexを環境変数で切り替える方法

  • Cloudflare Workers APIでカスタムドメインを設定する方法

  • DBから直接認証トークンを取得してE2Eテストを行う方法

対象読者

  • Cloudflare Workers + Next.jsで本番デプロイを行う方

  • NextAuth v5をCloudflare Workers上で動かす方

  • CI/CDパイプラインのデプロイエラーに対処する方

1. pgvector拡張の未インストール

症状

GitHub Actionsのデプロイで prisma db push が失敗。

Error: ERROR: type "vector" does not exist

原因

新規作成したPrisma PostgresのDBにpgvector拡張がインストールされていない。開発環境ではDockerの初期化スクリプトで自動インストールされていたため気づかなかった。

解決策

DIRECT_URL を使ってローカルからpgvector拡張をインストール。

psql '[DIRECT_URL]' -c 'CREATE EXTENSION IF NOT EXISTS vector;'

教訓

新規DBを作成した際は、マイグレーション前にpgvector等の拡張をインストールする手順をチェックリストに入れておく。

2. prisma db push の --accept-data-loss

症状

pgvector解決後も prisma db push が失敗。

Error: Use the --accept-data-loss flag to ignore the data loss warnings

原因

新規の空DBにスキーマをpushする際、unique制約の追加などが「データ消失の可能性がある変更」として検出される。

解決策

初回のみローカルから手動実行。CIのコマンドはそのまま維持。

DIRECT_URL='[接続文字列]' bunx prisma db push --accept-data-loss

注意

--accept-data-loss をCIに常設するのは危険。運用中にスキーマ変更した際、データが消える可能性がある。初回セットアップ時のみ手動で実行するのが安全。

3. Stripe環境変数未設定によるビルドエラー

症状

OpenNextビルドが失敗。

Error: STRIPE_SECRET_KEY environment variable is not set

原因

Stripeの初期化コードが起動時に環境変数を必須としてthrowしている。Stripe本番設定が完了していない段階でデプロイしたため発生。

解決策

ダミー値をGitHub Secretsに設定してビルドを通す。

gh secret set STRIPE_SECRET_KEY --env prod --body 'sk_test_dummy'
gh secret set STRIPE_PUBLISHABLE_KEY --env prod --body 'pk_test_dummy'
gh secret set STRIPE_WEBHOOK_SECRET --env prod --body 'whsec_dummy'
gh secret set STRIPE_PRICE_ID --env prod --body 'price_dummy'
📌
注意: ダミー値のままだと決済機能は動作しません。Stripeのビジネスオンボーディング完了後に本番キーに差し替えてください。

教訓

環境変数が未設定でもアプリがクラッシュしないよう、Stripeの初期化にガード処理を入れる設計も検討すべき。

4. NextAuth v5 の UntrustedHost エラー

症状

/api/auth/session が500エラーを返す。

原因の特定

wrangler tail でWorkerのログを確認。

npx wrangler tail [worker-name] --format json

ログに以下のエラー:

[auth][error] UntrustedHost: Host must be trusted. URL was: https://example.com/api/auth/session

原因

NextAuth v5はCloudflare Workers環境ではリクエストヘッダの host の扱いが通常のNode.jsサーバーと異なる。NEXTAUTH_URL を設定していても trustHost が明示的に必要。

解決策

NextAuthの設定に trustHost: true を追加。

export const { handlers, signIn, signOut, auth } = NextAuth({
  trustHost: true,  // ← これを追加
  adapter: PrismaAdapter(prisma),
  session: { strategy: "jwt" },
  // ...
});

教訓

Cloudflare Workers上でNextAuth v5を使う場合、trustHost: true は必須と考えた方がいい。

5. カスタムドメインのAPI設定

方法

Cloudflare Dashboardに行かなくても、APIで設定可能。

curl -X PUT \
  "https://api.cloudflare.com/client/v4/accounts/[ACCOUNT_ID]/workers/domains" \
  -H "Authorization: Bearer [API_TOKEN]" \
  -H "Content-Type: application/json" \
  -d '{"hostname":"example.com","service":"worker-name","environment":"production"}'
  • SSL証明書は自動発行

  • DNSがCloudflareで管理されていれば即時反映

6. robots/noindex の環境変数切り替え

課題

  • prod: 本来はSEO公開したいが、今はまだ非公開にしたい

  • dev: 常に非公開

  • 同じコードベースで環境ごとに制御したい

解決策

環境変数 ROBOTS_ALLOW で切り替え。

robots.ts:

export default function robots(): MetadataRoute.Robots {
  const isPublic = process.env.ROBOTS_ALLOW === "true";

  if (!isPublic) {
    return {
      rules: [{ userAgent: "*", disallow: ["/"] }],
    };
  }

  return {
    rules: [{
      userAgent: "*",
      allow: "/",
      disallow: ["/api/", "/admin/", "/mypage/", "/chat/", ...],
    }],
    sitemap: `${SITE_URL}/sitemap.xml`,
  };
}

layout.tsx:

robots: {
  index: process.env.ROBOTS_ALLOW === "true",
  follow: process.env.ROBOTS_ALLOW === "true",
  // ...
},

運用:

  • 非公開(デフォルト): ROBOTS_ALLOW を設定しない

  • 公開時: gh secret set ROBOTS_ALLOW --env prod --body "true" → 再デプロイ

7. DBからトークン取得でE2Eテスト

課題

メール認証フローのあるアプリで、PlaywrightによるE2Eテスト時にログインできない。

解決策

DBに直接ログイントークンを作成し、Playwrightでそのトークンを使ってログインする。

-- 有効期限10分のログイントークンを直接作成
INSERT INTO "VerificationToken" (identifier, token, expires)
VALUES ('login:[email protected]', 'e2e-test-token', NOW() + INTERVAL '10 minutes');
// Playwrightでトークンを使ってログイン
await page.goto('https://example.com/api/auth/verify-login?token=e2e-test-token');
await page.waitForURL('**/chat**');

メリット

  • メール送信を待つ必要がない

  • CI/CDでも自動テスト可能

  • トークンの有効期限を自由に設定できる

Tips

📌
Tip 1: wrangler tail --format json でWorkerのログをリアルタイム確認できる。本番環境のデバッグに非常に便利
📌
Tip 2: Terraform の -target オプションで依存関係のないリソースだけ先にapplyできる。例: terraform apply -target=module.r2
📌
Tip 3: GitHub Secretsの値はCLIからも確認不可。パスワードマネージャーに別途保存しておくこと
📌
Tip 4: Stripe本番申請前に特定商取引法に基づく表示ページが必要。利用規約・プライバシーポリシーだけでは不十分

まとめ

  • pgvector: 新規DB作成後に CREATE EXTENSION IF NOT EXISTS vector; を忘れずに

  • prisma db push: 初回は --accept-data-loss が必要だが、CIには入れない

  • NextAuth v5 + Workers: trustHost: true は必須

  • Stripe未設定: ダミー値でビルドを通し、後から差し替え

  • robots.txt: 環境変数で公開/非公開を切り替え。コード変更不要

  • E2Eテスト: DB直接操作でメール認証をバイパス可能