ガイド 第41

デプロイ & cron

Vercel CLI・CRON_SECRET・セキュリティヘッダ

@event/core

デプロイは Vercel CLI だけで完結する(GUI 不要)。monorepo の 1 app を公開し、任意ドメインを Cloudflare か Route53 で向ける。定期実行は @event/corewithCronAuth で保護する。完全手順は レシピ deploy-vercel、ここは要点と cron を解説する。

Vercel CLI デプロイ(monorepo)

Root Directory は CLI から設定できないので、repo root に vercel.json を置いて回避する:

{
  "framework": "nextjs",
  "installCommand": "yarn install --frozen-lockfile",
  "buildCommand": "yarn turbo build --filter=<app>",
  "outputDirectory": "apps/<app>/.next"
}

罠 2 つ: ① Root Directory を CLI で指定できない → 上の vercel.json で解決。② ドメインはそれを所有する Vercel team の scope でしか add できない(別 team だと 403 domain_not_owned)。vercel deploy --prod --scope <team>vercel domains add <domain> --scope <team>。DNS は A 76.76.21.21 を 1 本 (Cloudflare は DNS-only で証明書発行を通してから Proxied 化)。

cron 保護 — withCronAuth / isCronAuthorized

vercel.jsoncrons[] で叩く定期エンドポイントは、必ず @event/corewithCronAuth で包む。 Authorization: Bearer ${CRON_SECRET}厳格一致のみを通す:

import { withCronAuth } from "@event/core";

// app/api/cron/sync/route.ts
export const GET = withCronAuth(async (req) => {
  // …定期同期処理…
  return Response.json({ ok: true });
});
// vercel.json
{ "crons": [{ "path": "/api/cron/sync", "schedule": "0 * * * *" }] }
  • CRON_SECRET 未設定なら 503 CRON_SECRET not configured(誤って無防備公開しない fail-closed)
  • 判定だけ欲しいときは isCronAuthorized(req, { secret? })(既定 env CRON_SECRET
  • Vercel Cron は自動で Bearer を付与する。手動叩きは curl -H "Authorization: Bearer $CRON_SECRET"

セキュリティヘッダはデプロイ時に自動

createNextConfig(第40章)が CSP / HSTS / COOP / Permissions-Policy を全レスポンスに付与する。 デプロイ後 curl -I https://<domain>content-security-policy 等が出ることを確認する。新しい外部ホスト (分析・フォント)を足したら next.config.tssecurity.csp フラグで許可する(ハードコードしない)。

本番反映のルール

vercel git connect で GitHub を繋ぐと main への push = 本番反映。作業は必ずブランチ → PR。Vercel は squash/rebase で author 保持が崩れると deploy blocked になることがあるため merge commit 推奨。

observability(現状)

専用の observability パッケージは持たない。実装済みは createNextConfigremoveConsole(本番は error/warn を残して他を除去)と Vercel 標準の Build/Runtime Logs。構造化ログ・トレースの導入は 将来の拡張ポイント(現状は未実装)。