Azure Static Web Apps の GitHub Actions デプロイが Invalid API key で失敗する原因と解決策(Next.js)

Azure Static Web Apps に Next.js を GitHub Actions でデプロイすると、ビルドは通るのに最後だけ「Invalid API key」で落ちることがあります。トークン再生成やSecrets更新でも直らない場合に効く“作り直し”と、その後に出がちな「Web app warm up timed out」までまとめて解決します。

目次

このトラブルが厄介な理由

「Invalid API key」は名前の通りトークンの間違いを疑うエラーですが、実際には GitHub Actions 側の設定が正しくても、Static Web Apps 側の初期構成が原因で失敗するケースがあります。特に次の条件に当てはまると、時間だけが溶けがちです。

  • GitHub Actions のログ上は ビルド完了・成果物のアップロード完了まで進む
  • 最後のデプロイ確定フェーズで Deployment Failure Reason: Invalid API key
  • AZURE_STATIC_WEB_APPS_API_TOKEN は GitHub Secrets に入っている
  • トークン再生成、Secrets の更新、YAML の参照名確認をやっても改善しない

まずは切り分け:本当に「単純な設定ミス」ではないか確認

今回紹介する根本対処に進む前に、5分で終わる確認だけ済ませておくと安心です。ここで引っかかる場合は「作り直し」不要で直ることがあります。

確認ポイントよくある落とし穴確認方法
Secrets の参照先リポジトリSecretsではなく Environment Secrets に入れていて参照できていない/逆もあるWorkflow がどの Environment を使うか、Secrets のスコープが一致しているか確認
Secret 名AZURE_STATIC_WEB_APPS_API_TOKEN の綴り違い(末尾のS、アンダースコア)YAML で ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }} になっているか
デプロイ先別の Static Web App のトークンを入れている(環境が複数あると起きやすい)Azure 側の対象リソース名と、トークン取得元が一致しているか
Workflow の action 指定action: "upload" が抜けていたり、古いテンプレが混ざっているAzure/static-web-apps-deploy の例と比較

それでも解消しない場合、ここからが本題です。ポイントは「トークンそのもの」ではなく、Static Web Apps の作り方(初期の連携方式)にあります。

Invalid API key の根本原因:GitHub 連携で作った Static Web Apps が“トークン方式”と噛み合わない

結論から言うと、このパターンの「Invalid API key」は トークンが間違っている/期限切れというより、Static Web Apps の作成時に GitHub 連携(GitHub App 連携)で構成を作ったことが原因で、期待通りにトークンが通らない状態になっているケースがあります。

実際、次のような状況が同時に起きると、表面上は「トークン問題」に見えます。

  • Azure Portal 側で GitHub 連携を選んで Static Web Apps を作成した
  • その後、リポジトリ構成を変えた(monorepo化、ディレクトリ移動、別リポジトリへ移行など)
  • Workflow を手で書き換えたり、Secrets を一般名(AZURE_STATIC_WEB_APPS_API_TOKEN)に統一した
  • しかしデプロイ段階だけが通らない

このときの最短ルートは、原因探しを延々と続けるより 「Deployment token(デプロイトークン)方式」で Static Web Apps を作り直し、そこで生成された新しいトークンでデプロイすることです。

対処:Deployment token 方式で Static Web Apps を作り直す

手順はシンプルですが、“作成時の選択”が一番重要です。ポイントは「GitHub 連携」ではなく、デプロイトークンでデプロイする前提の構成で作ること。

作り直し手順(要点)

  1. Azure Portal で新規に Static Web Apps を作成する
  2. 作成時のデプロイソース(デプロイ方法)の選択で、GitHub 連携ではなく Deployment token(または Other / Manual deployment 相当)を選ぶ
  3. 作成後、Static Web Apps の「Deployment token」から トークンを取得する(必要なら再生成)
  4. GitHub リポジトリの Secrets に AZURE_STATIC_WEB_APPS_API_TOKEN として登録する
  5. Workflow の azure_static_web_apps_api_token がその Secrets を参照していることを確認する

ここでの肝は「トークンを再生成する」ではなく、最初から“トークン方式の Static Web Apps”として作り直す点です。これで「Invalid API key」が解消することがあります。

作り直し時の移行チェック

作り直しは即効性がある一方で、運用中の環境だと移行ポイントを押さえておかないと手戻りします。最低限、次をチェックしてから切り替えると安全です。

移行項目影響やること
既存の公開URL既定ドメインは変わるURLを固定したい場合はカスタムドメイン運用に寄せる
カスタムドメイン再設定が必要になることがあるDNS設定、証明書状態、ドメイン検証を事前に確認
認証(ログイン連携)プロバイダ設定が紐づく利用している場合は設定内容を控えておき、新環境へ再設定
アプリ設定(環境変数)静的エクスポートでは特に重要どの値がビルド時に必要かを整理し、GitHub Secrets/Variablesへ反映
PRプレビュー環境運用方法が変わるプレビューが必要ならWorkflowとブランチ戦略も同時に見直す

GitHub Actions 側の設定例(最小構成)

Workflow は最終的にこの形に寄せると安定します(Next.js のビルド方法は後述)。

name: Azure Static Web Apps CI/CD

on:
  push:
    branches:
      - main

jobs:
  build_and_deploy:
    runs-on: ubuntu-latest
    name: Build and Deploy
    steps:
      - uses: actions/checkout@v4

      - name: Deploy
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
          repo_token: ${{ secrets.GITHUB_TOKEN }}
          action: "upload"
          app_location: "/"
          api_location: ""
          output_location: "out"

※今回は「そこが原因ではない」ケースですが、一般的な確認として azure_static_web_apps_api_token が Secrets を正しく参照しているかは必ずチェックしてください。

Invalid API key 解消後に出やすい次の壁:Web app warm up timed out

「Invalid API key」が解消すると、次に以下へ移行することがあります。

  • Deployment Failure Reason: Web app warm up timed out

このエラーは、Static Web Apps がデプロイされたアプリを「起動確認(ウォームアップ)」しようとしたときに、期待した応答が返らずタイムアウトした状態を示します。Next.js では SSR(サーバーサイドレンダリング)前提の構成が混ざっていると発生しやすいです。

原因:Next.js が“静的サイトとして完結していない”

Static Web Apps は基本的に 静的ホスティングです。Next.js をそのまま載せると、プロジェクトの設定や機能の使い方によっては「実行時サーバーが必要なアプリ」になり、Static Web Apps の前提と衝突します。

特に、次の要素があると要注意です。

要素何が起きるか結果
rewrites を Next.js 側で使用SSR/ランタイム相当の振る舞いを期待したルーティングになる静的エクスポートで成立せず、ウォームアップ失敗につながりやすい
成果物が .next 前提Node サーバーで動かす前提のビルド成果物になりがちStatic Web Apps の「静的ファイル配信」とミスマッチ
動的データ取得(SSR必須)リクエストごとにサーバー処理が必要静的ホスティングでは再現できない

対処は、Static Web Apps に無理に合わせるなら 「静的として成立させる」ことです。

対処:Next.js を静的エクスポート向けに寄せる

ここからは「Static Web Apps で安定稼働させる」ための現実的な落とし所です。Next.js のすべての機能が使えるわけではありませんが、構成がハマると CI/CD は一気に安定します。

Next.js 設定:output: 'export' を追加し、rewrites をやめる

next.config.ts を静的エクスポート前提に変更します。最小構成は次の通りです。

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  output: "export",
  // 画像最適化を使っている場合は静的エクスポートでは追加調整が必要になることがあります
  // images: { unoptimized: true },
};

export default nextConfig;

重要:rewrites は削除(または少なくとも静的エクスポート前提の設計へ変更)します。Next.js の rewrites は「サーバーがルーティング処理をしてくれる」前提で組まれがちで、Static Web Apps の静的配信とは相性が悪いです。

Workflow の出力先:output_location を .next から out へ

静的エクスポートを有効にすると、デプロイすべき成果物は基本的に out 配下になります。GitHub Actions の設定もそれに合わせます。

項目SSR寄りの設定静的エクスポート設定
出力フォルダ.nextout
Workflow の output_location.nextout

実際の Workflow では次のように指定します。

output_location: "out"

API 呼び出し:rewrites ではなく環境変数で“直接”呼ぶ

rewrites で「フロントは同一オリジンの /api を叩けば裏でバックエンドへ流れる」という作りにしていると、静的エクスポートへ寄せた瞬間に設計が崩れます。

そこで、フロント側は NEXT_PUBLIC_API_URL のような環境変数を使い、Azure App Service やコンテナ等のバックエンドへ 直接リクエストする形に変更します。

// 例:API クライアントのベースURLを環境変数から組み立てる
const baseUrl = process.env.NEXT_PUBLIC_API_URL;

export async function fetchUser() {
  const res = await fetch(`${baseUrl}/users/me`, {
    headers: { "Content-Type": "application/json" },
  });

  if (!res.ok) throw new Error("API request failed");
  return res.json();
}

静的エクスポートで特に注意:Next.js の NEXT_PUBLIC_ 付き環境変数は “ビルド時に埋め込まれる” 性質があります。つまり、Azure Portal 側で後から値を変えても静的HTMLには反映されません。運用するなら次のどちらかに寄せると事故が減ります。

  • GitHub Actions のビルド時に環境変数を渡して固定する(環境ごとにSecretsを分ける)
  • 実行時に読み込む config.json のようなファイルを用意し、フロントはそれを読んでURLを決める(静的でも差し替え可能)

Static Web Apps 側のルーティング設定で補う

Next.js の rewrites を外すと「SPA の直リンクで 404 になる」「ヘッダーやキャッシュを制御したい」など、別の困りごとが出ることがあります。その場合は、Static Web Apps のルーティング設定(staticwebapp.config.json)で補うのが現実的です。

例えば、クライアントサイドルーティングのある構成で直リンクを許可したい場合は、次のような設定が使われます。

{
  "navigationFallback": {
    "rewrite": "/index.html",
    "exclude": ["/assets/*", "/favicon.ico"]
  }
}

※ここでできるのは主に「配信側のルール制御」です。バックエンドへの“透過的なプロキシ”を Next.js の rewrites と同じ感覚で置き換えるのは難しいため、API は原則として直接呼ぶ(または別のゲートウェイを用意する)方が運用が安定します。

静的エクスポートでハマりがちなポイント

「設定を変えたらビルドが通らない/動かない」を防ぐために、静的エクスポートで制約になりやすい要素をまとめます。該当する機能がある場合は、早めに設計を切り替えるのが得策です。

機能・要素静的エクスポートでの扱い回避・代替案
SSR(リクエストごとに描画)基本的に不向きSSG/ISR相当へ寄せる、またはSSR対応ホスティングへ移行
Next.js の rewrites期待通りに動かないことがあるAPIは直接呼ぶ/必要なら別サービスでルーティング統合
API Routes(pages/api など)静的だけでは完結しないAzure Functions や App Service に分離して運用
next/image の最適化サーバー機能が必要になりやすいunoptimized 設定、外部画像CDN、事前最適化
環境変数の切り替えビルド時埋め込みで事故が起きやすいビルド時に注入する/実行時に読む設定ファイル方式

実務で効く:エラーから逆引きするチェックリスト

似たログでも原因が違うことがあるので、現場で使えるように “症状→当たりどころ” を表にまとめます。

症状(ログ)疑うポイント最短のアクション
ビルド完了→アップロード完了→最後だけ Invalid API keyStatic Web Apps の作成方法(GitHub連携の初期構成)が噛み合っていないDeployment token 方式で新規作成→新トークンで Secrets 更新
Invalid API key が突然出る(以前は動いた)トークンの再生成、Secrets の上書きミス、別環境のトークン混入トークン取得元を確認→Secrets を貼り直し→Workflow の参照名を再確認
Web app warm up timed outNext.js が静的として成立していない(SSR、rewrites、出力先の不一致)output: "export"、output_location: "out"、rewrites削除
デプロイは成功するが画面が真っ白/404SPA ルーティング設定、ベースパス、静的ファイルの配置ミスout に index.html があるか確認→staticwebapp.config.json を見直す

Static Web Apps と Next.js を組み合わせるときの設計判断

最後に、同じところで迷う人が多い「Static Web Apps を使い続けるべきか」の判断軸を整理します。ここを最初に決めると、エラー対応が “その場しのぎ” になりません。

SSRを維持したいなら無理に Static Web Apps に寄せない

SSR(rewrites含む)を維持したいなら、Static Web Apps に無理に寄せるより、Next.js を自然に動かせるホスティング(Azure App Service、コンテナ、Vercel など)を検討した方がトラブルは減ります。Static Web Apps は “静的が主役” のサービスなので、SSR を前提にすると構成が複雑化しやすいです。

Static Web Apps を使うなら「静的として完結」か「バックエンド分離」

Static Web Apps を選ぶ場合は、次のどちらかに寄せるのが安全です。

  • 静的として完結させる:CMS的な更新はビルドで反映、ページは SSG / 静的エクスポートで配信
  • バックエンド分離で直接呼ぶ:フロントは静的、API は App Service / Functions / Container Apps など別サービスで運用
要件おすすめ理由
SEO重視の静的サイト(更新頻度はそこまで高くない)Static Web Apps + Next.js 静的エクスポート配信が速い、運用が軽い、GitHub Actions と相性が良い
ログイン後のダッシュボード中心(API 依存が強い)Static Web Apps + バックエンド分離フロントは静的で十分、API は別でスケールさせやすい
SSR必須(リクエストごとに描画内容が変わる)App Service / コンテナ / SSR対応ホスティングStatic Web Apps の前提と衝突しやすく、タイムアウト系トラブルが出やすい

まとめ:今回の最短解は「トークン」ではなく「作成方式」と「静的成立」

「Invalid API key」は Secrets やトークン再生成で直ることもありますが、ビルド~アップロードまで成功して最後だけ落ちる場合は、Static Web Apps 側の初期構成が原因になっていることがあります。その場合は Deployment token 方式で作り直し、新トークンでデプロイが最短です。

さらに「Web app warm up timed out」に進んだら、Next.js の設定が SSR 寄りになっていないかを疑い、静的エクスポート(output: "export")と output_location: "out" を軸に構成を整えると安定します。Static Web Apps は “静的が主役” と割り切り、バックエンドは分離して設計するのが実務的に強い選択です。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次