Next.js + Railway + n8n でAIチャット秘書を実装した記録 — MS Teams連携を諦めChat Triggerで完成


目次

結論から

Next.js のコーポレイトサイトの右下に、Anthropic Claude が応答するAIチャット秘書を埋め込みました。

構成は以下のとおりです。

  • フロントエンド: Next.js 15 (App Router) on Vercel
  • チャットウィジェット: @n8n/chat パッケージ
  • バックエンド: n8n (Chat Trigger + AI Agent + Anthropic Chat Model) on Railway
  • LLM: Anthropic Claude Sonnet 4.5

最終構成は驚くほどシンプルです。動くものを作る所要時間は約2時間、月額運用コストは約¥1,000〜¥5,000(利用量による)程度に収まります。

ただし、ここに至るまでに Microsoft Teams 連携で2日溶かしました。事業として中小企業向けに展開する想定だったのでTeamsから入りましたが、個人開発者の検証環境では構造的に通らない地雷が無数にありました。

この記事では、最終構成の実装手順を先にお示ししてから、なぜTeamsを諦めたか、その過程で踏んだ8個の地雷を共有します。動くものを早く欲しい方は前半だけ、設計判断の参考が欲しい方は後半までお読みください。


全体アーキテクチャ

責務分離が綺麗に効いています。

  • Vercel: 静的アセット配信とSSR、Edge Functionsで即応答
  • Railway: n8nの常駐サーバープロセス、永続化が必要なステート管理
  • Anthropic: LLM推論

それぞれの得意領域で動かしています。Vercelにn8nをデプロイしようとしてはいけません(理由は後述します)。


Phase 1: Railway で n8n をデプロイ

なぜ Railway か

n8n の常駐サーバー型アーキテクチャ(Express + データベース + 永続ボリューム)はサーバーレス環境(Vercel、Cloudflare Workers等)と根本的に相性が悪いのです。Railway は Docker コンテナをそのままデプロイできる「Vercel for backends」的なPaaSで、n8n との相性が抜群です。

観点VercelRailway
実行モデルサーバーレス関数(冷起動あり、最大10〜60秒)常駐コンテナ(WebSocketも可)
永続ストレージなしボリューム付き
データベース外部接続前提PostgreSQL/Redisがクリックで追加可能
n8n動作❌ 不可✅ 公式テンプレートあり

デプロイ手順

Railway は GitHub アカウントでログインするのが標準です。

  1. https://railway.com → “Login with GitHub”
  2. ダッシュボード → 「+ New」「Deploy from Template」
  3. 検索ボックスに n8n と入力
  4. 公式系のテンプレート(n8n (w/ postgres) 等、Railway ロゴ付き)を選択
  5. 「Deploy」 をクリック
  6. PostgreSQL と n8n の2サービスが自動構築される(3〜5分)

Public Domain の発行

Railway UI が頻繁に変わるので、ボタン名は微妙に違うかもしれません。執筆時点(2026年4月)の手順は次のとおりです。

  1. n8n サービスをクリック
  2. Settings → Networking セクション
  3. 「Generate Domain」 または 「+ Public Networking」 をクリック
  4. ポート番号を聞かれたら 5678(n8nデフォルト)
  5. xxx-production.up.railway.app のような公開URLが発行される

⚠️ ここで注意点があります。画面トップに 「Get a domain」 という似たボタンがありますが、これは Railway のドメイン販売ページに飛ばされる別物です。Settings 内の Networking セクションから発行してください。

環境変数

Railway がほとんど自動で設定してくれますが、追加しておくと良いものがあります。

GENERIC_TIMEZONE=Asia/Tokyo
TZ=Asia/Tokyo
N8N_DEFAULT_LOCALE=ja      # UIを日本語化(任意)

WEBHOOK_URLN8N_HOST は Railway が自動で正しい値を入れてくれます。設定がシンプルで済むのがRailway 移行の最大のメリットです。

動作確認

ブラウザで発行されたURLを開くと、n8nのオーナーアカウント作成画面が表示されます。完了するとダッシュボードに遷移します。

これで n8n 本体のデプロイは完了です。


Phase 2: n8n でチャットワークフロー作成

ノード構成

最小構成は以下の3ノード(+1サブノード)です。

Step 1. Chat Trigger ノード

⚠️ n8n 2.x で名前が変わっています。検索すると次のような名称になっています。

  • 旧: Chat Trigger
  • 新: When chat message received または検索結果トップの Chat

これらは同じノードです。最初検索しても見つからずに焦るので注意してください。

設定は次のとおりです。

項目備考
Make Chat Publicly AvailableONこれを ON にしないとWebhookが外部からアクセス不可
Make Available in n8n Chat HubOFF別機能、不要
Initial Messages (任意)「こんにちは!何かお手伝いできることはありますか?」Add Field から追加

Step 2. AI Agent ノード

+ から AI Agent を検索して追加します。Tools Agent モードを選択してください。

System Message に以下を貼り付けます(JST解釈と機能制限を明示しています)。

あなたはNeuroSynch社の社内秘書アシスタントです。
ユーザーの自然言語の指示や質問に、簡潔・丁寧・敬語で応答してください。

ルール:
- 質問には簡潔に答える(冗長な前置きは不要)
- 日時の解釈はJST(Asia/Tokyo)基準
- 現在時刻は {{ $now.toISO() }} です
- わからないことは「わかりません」と正直に答える
- スケジュールやタスクの登録依頼が来た場合は「現在この機能は準備中です。
  カレンダーやタスクツールへの直接登録をお願いします」と返答する

Source for Prompt (User Message)Connected Chat Trigger Node のままで問題ありません。Chat Trigger 側のメッセージ本文が自動で入ります。

Step 3. Anthropic Chat Model(サブノード)

AI Agent の Chat Model スロット(◇マーク、下にぶら下がる)に追加します。

項目
ModelClaude Sonnet 4.5 (claude-sonnet-4-5-20250929)
Maximum Number of Tokens2048
Temperature0.3
Enable ThinkingOFF

⚠️ Enable Thinking を ON にすると tool_use と組み合わせた時に 400 エラーになる既知バグがあります(n8n issue #15715)。Tools Agent と組み合わせる場合は必ず OFF にしてください。今回はツール無しなので影響しませんが、後々ツール追加した時に踏むので最初から OFF を推奨します。

⚠️ モデル名についての注意があります。古い記事に出てくる claude-sonnet-4-20250514(Sonnet 4.0) と claude-opus-4-20250514(Opus 4.0) は 2026年6月15日で廃止されます。新規構築では Sonnet 4.5 / Opus 4.7 系を使ってください。

Step 4. Publish

ワークフロー右上の 「Publish」 をクリックします。

⚠️ Test workflow ボタンでは Chat Trigger は本番URLで動作しません。Test URLは「Execute workflow ボタン押下後の1回限り」しか有効ではないため、Microsoft Graph 等の外部からの定常的な検証POSTを受け取れないためです。必ず Publish して Production URL を有効化してください。

Publish後、Chat Trigger ノードを開くと、Production URL が表示されます。

https://xxx-production.up.railway.app/webhook/{chatId}/chat

このURLをブラウザで直接開くと、n8n標準のチャットUIが即座に使えます。これだけでも十分機能します。


Phase 3: Next.js への埋め込み

n8n 標準のチャットUIをそのまま <iframe> で埋め込むこともできますが、自社サイトのデザインに馴染ませたいので @n8n/chat パッケージ(右下に浮かぶ吹き出しUI)を使います。

Step 1. パッケージインストール

npm install @n8n/chat

Step 2. 環境変数設定

URLをコードに直書きせず、環境変数で管理します。

.env.local(ローカル開発用)に以下を追加します。

NEXT_PUBLIC_N8N_CHAT_WEBHOOK_URL=https://xxx-production.up.railway.app/webhook/yyyyyyyy/chat

⚠️ NEXT_PUBLIC_ プレフィックスが必須です。これがないとクライアントサイドで参照できません。

Vercel ダッシュボード → Settings → Environment Variables にも同じ変数を Production / Preview / Development 全てに登録してください。

Step 3. コンポーネント実装

src/components/N8nChat.tsx を作成します。

TypeScript
'use client';

import { useEffect } from 'react';
import { createChat } from '@n8n/chat';
import '@n8n/chat/style.css';

export default function N8nChat() {
  useEffect(() => {
    const webhookUrl = process.env.NEXT_PUBLIC_N8N_CHAT_WEBHOOK_URL;

    if (!webhookUrl) {
      console.warn('NEXT_PUBLIC_N8N_CHAT_WEBHOOK_URL is not set');
      return;
    }

    createChat({
      webhookUrl,
      mode: 'window',
      showWelcomeScreen: false,
      defaultLanguage: 'en',
      initialMessages: [
        'こんにちは!NeuroSynch のAI秘書アシスタントです。',
        'ご質問やご相談がありましたら、お気軽にどうぞ。',
      ],
      i18n: {
        en: {
          title: 'NeuroSynch AI Assistant',
          subtitle: 'お気軽にご質問ください',
          footer: '',
          getStarted: 'チャットを開始',
          inputPlaceholder: 'メッセージを入力...',
          closeButtonTooltip: '閉じる',
        },
      },
    });
  }, []);

  return null; // UI自体はcreateChatが直接DOMに挿入する
}

⚠️ defaultLanguage: 'en' にして i18n.en で日本語を上書きしているのは、@n8n/chat の i18n 機構の都合によるものです。'ja' を直接指定すると一部翻訳が効かないバージョンがあるため、英語をベースに日本語を流し込む形が安定します。

Step 4. レイアウトに組み込む

src/app/layout.tsx を編集します。

TypeScript
import N8nChat from '@/components/N8nChat';

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ja">
      <body>
        {children}
        <N8nChat />
      </body>
    </html>
  );
}

Step 5. CORS設定

n8n 側で、Vercel のドメインからのリクエストを許可します。

Chat Trigger ノードを開いて Allowed Origins (CORS) に追加してください。

http://localhost:3000,https://your-project.vercel.app,https://www.neurosynch.co.jp

⚠️ 検証中につい * で広く許可したくなりますが、本番では必ずドメインを絞ってください。* のままだと第三者が自分のサイトに勝手に埋め込んでAPI課金を発生させる可能性があります。

Step 6. デプロイ

git add .
git commit -m "Add n8n chat widget"
git push origin add-n8n-chat

GitHub プルリクエスト → Vercel が自動で Preview URL を発行 → 動作確認 → main にマージで Production 反映、という流れです。


ここまでで完成

これで Next.js コーポレイトサイトの右下に AI チャット秘書が常駐する状態になります。所要時間は概ね2時間です。


後半: なぜ Microsoft Teams を諦めたか

ここからは「なぜ最初にこの構成にしなかったか」「なぜTeamsから入って2日溶かしたか」のお話です。同じ轍を踏みたくない開発者の方向けに共有します。

当初の設計

事業として中小企業向けにAI秘書を提案する想定だったので、Teams連携が一番説得力があると考えていました。「社員が普段使っているTeamsで動く」は、提案デモのキャッチーさで言えば最強です。

n8n は Microsoft Teams Trigger ノードを公式提供しており、ドキュメント上は「OAuth2でアプリ登録するだけ」と書かれています。30分〜1時間で動くと見積もっていました。

これが甘かったです。

ハマりどころ8選

時系列で淡々と記録していきます。各項目につき、症状/原因/対処/所要時間を共有します。

1. Azure App Registration “deprecated outside directory”

The ability to create applications outside of a directory has been deprecated.

個人 Microsoft アカウント(outlook.com)のままでは Azure Entra ID にディレクトリが存在しないため、App Registration を作れませんでした。Azure無料サインアップで Default Directory を作るか、M365 Business 契約が必要になります。

所要時間: 30分

2. Supported account types で Multitenant 必須

AADSTS50194: Application is not configured as a multi-tenant application.
Usage of the /common endpoint is not supported for such applications

n8n の Microsoft Teams OAuth2 は OAuth エンドポイントとして /common/(マルチテナント用)を固定で使う実装になっています。よって Azure 側のアプリは 「Single tenant」では絶対に動かず、Multitenant 設定が必須になります。

これはn8n公式ドキュメントにもMicrosoft公式ドキュメントにも明示されておらず、エラーメッセージから逆引きするしかありませんでした。

所要時間: 30分

3. Manifest accessTokenAcceptedVersion = 2

Failed to update application. Error detail: Property api.requestedAccessTokenVersion is invalid.

Multitenant + 個人アカウント許可に変更しようとすると、Manifest の accessTokenAcceptedVersion が古い値のままだとエラーになります。Manifest を直接編集して 2 に書き換えてから保存し直す必要があります。

所要時間: 20分

4. Client Secret の Value vs Secret ID 取り違え

AADSTS7000215: Invalid client secret provided.
Ensure the secret being sent in the request is the client secret value, not the client secret ID

Azure の Certificates & secrets 画面では、新規発行した Secret に Value 列と Secret ID 列の両方が表示されます。両方ともコピーアイコンが付いているため、間違えて Secret ID をコピーしてしまうと認証エラーになります。使うのは Value 側(チルダ ~ を含む短い文字列)です。

所要時間: 15分(原因特定に時間がかかりました)

5. OAuth Redirect URL の不一致(localhost vs ngrok)

n8n の OAuth Redirect URL の表示が http://localhost:5678/... のままだったため、Azure に登録した ngrok URL と一致せず認証失敗していました。

原因は docker-compose.ymlWEBHOOK_URL が反映されていなかったことです。環境変数を更新後、docker compose down && docker compose up -d で再起動すれば反映されます。

所要時間: 30分

6. Credential ID の古参照(削除しても残る)

Credential with ID "LtYhF3vN9dkx4CAB" does not exist for type "microsoftTeamsOAuth2Api".

Credential を削除して新規作成しても、ワークフローのノードは内部的に古いCredential ID を保持し続けることがあります。UI上で「同じ名前」のCredentialがドロップダウンに表示されているので「再選択」したつもりでも、IDが書き換わらないことがあります。

対処: ノードを完全に削除して、Credential を選択し直しながらノードごと再作成してください。

所要時間: 60分(原因特定に時間がかかりました)

7. Test URL は1回限り、Microsoft Graph検証POSTは404

Microsoft Teams Trigger を Test workflow で動かすと、n8n は Test URL(/webhook-test/...)を Microsoft Graph に Subscription として登録します。しかし Test URL は 「Execute workflow ボタン押下後の1回限り」 しか有効ではないため、Microsoft Graph が定期的に送る再検証POSTで毎回404が返り、Subscription が即時失敗していました。

対処: 必ず Publish して Production URL(/webhook/...)を使ってください。

これは公式ドキュメントに明示されておらず、エラーメッセージから推測するしかありませんでした。

所要時間: 90分

8. Subscription登録の沈黙失敗

ここまでクリアしても、GET https://graph.microsoft.com/v1.0/subscriptions で Subscription が空のまま登録されない症状が出ました。docker logs を見ると Credential with ID "..." does not exist のエラーが残っており、削除したはずの古いワークフローのバックグラウンドタスクが Subscription 登録処理を妨害していました。

対処:

  1. すべてのワークフローを Inactive 化
  2. docker compose down && docker compose up -d で完全再起動
  3. 古いワークフローを削除
  4. 新規作成し直す

n8n は内部的にワークフローごとのバックグラウンドプロセスを保持するため、「削除しただけ」では完全に止まらないことがあります

所要時間: 60分

累計

8個のハマりどころで、合計 約6時間(原因特定の試行錯誤時間込みで実質2日)かかりました。

最終的には、これらをすべて回避してもなお 「個人アカウントの Neurosynch テナントでは Subscription が安定登録されない」 症状が続いたため、Teams連携を断念しました。

n8n コミュニティの GitHub Issue (#16751, #17887, #22575等) でも同様の症状が複数報告されており、2025年後半からの構造的不安定性が疑われます。個人開発者の検証環境では推奨できません


教訓と設計判断

ハマり譚から得た知見をまとめます。

1. 「動くものを最短で出す」設計を最初に組む

最終的に動いた構成は2時間で完成しました。最初からこの構成を選んでいれば、2日節約できました

検証段階では、「摩擦が最も少ない宛先」を選ぶのが正解だと感じています。Teamsのような大企業向けエンタープライズ統合は、検証段階では選んではいけません。検証完了後、必要があれば移行する形が現実的です。

2. ノーコードは「楽」ではない

n8n は確かにコードを書く量を減らしてくれますが、設定地雷の数は変わりません。むしろ、コードベースなら IDE のエラー表示や型チェックで早期に気付ける問題が、UIベースだと「沈黙失敗」になることが多いと感じました。

ノーコード/ローコードツールを選ぶ判断は、「コードを書きたくないから」ではなく、「設計の見える化と保守性」を理由にすべきだと思います。

3. docker logs は最強のデバッグツール

n8n のUI上では「成功した」ように見える操作が、内部的にはバックグラウンドで失敗していることが多いです。docker logs n8n-secretary-n8n-1 --tail 50 を打つだけで、UIには出ないエラーの大半が見えます。

ngrok の場合は http://127.0.0.1:4040 でリクエストの方向(送受信)を切り分けると、問題が「自分側」か「相手側」かが30秒で判明します。

4. クラウドサービスの「実行モデル」を理解しないと選定を間違える

Vercel に n8n をデプロイしようとしてはいけません。これは Vercel が悪いわけではなく、「サーバーレス vs 常駐コンテナ」というアーキテクチャ的な違いを理解せずに選ぶと、後で大きな手戻りになるためです。

用途適切な宛先
静的・SSR WebサイトVercel, Netlify, Cloudflare Pages
Edge FunctionVercel Functions, Cloudflare Workers
常駐サーバー(Node.js, Python等)Railway, Render, Fly.io, VPS
データベースSupabase, Neon, PlanetScale, RDS

「フロントもバックエンドも全部Vercelで」と考えがちですが、バックエンドの性質によって適切な宛先は変わります

5. Microsoft Teams連携は組織テナント前提で設計されている

これは構造的な事実です。個人アカウントや小規模事業者の検証環境では、Subscription機能の権限まわりが微妙に不安定で、根本対処は困難でした。

中小企業納品時には、顧客側のM365 Business契約済みテナントで実装すれば普通に動きます。「自社の検証環境では別の宛先で動かし、納品時に顧客テナントへ移植する」という運用が現実的です。


拡張ポイント

完成したMVPに乗せられる拡張は多数あります。優先度順にまとめました。

機能追加方法想定工数
会話メモリ(継続文脈)Window Buffer Memory ノード追加30分
スケジュール/タスク管理Supabase + 専用Toolノード4時間
朝のサマリー自動配信Schedule Trigger → メール送信1時間
社内ナレッジRAGSupabase Vector Store + Embeddings6時間
MCP連携(freee/MF等)n8n MCP Client ノード追加4時間
認証(社内専用にする)Chat Trigger の Authentication 設定30分

特に Memory 追加は30分で会話の継続性が劇的に向上するので、本番運用前にはやっておきたいところです。


まとめ

  • AIエージェントを業務やWebに組み込む現実解は、**「動くものを最短で出して効果検証する」**設計です
  • Microsoft Teams連携は構造的に不安定で、検証フェーズには向きません
  • Vercel + Railway + n8n の構成なら、月¥1,000〜¥5,000、2時間でAIチャット秘書を本番化できます
  • 設定ハマりの大半は docker logs と ngrok管理画面で30秒で原因特定できます


よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

1981年生まれ、名古屋出身。
2008年より17年間ドイツ・ベルリンに在住。
ドイツの職業訓練プログラムを修了後、複数のIT企業でフルスタックエンジニアとして経験を積む。2022年よりドイツの大手システム開発会社で、リードエンジニアとして勤務する。小売・医療・メディアなど異なる業種に携わる。2026年6月株式会社Neurosynchを設立。2027年、日本に帰国予定。
著書「AI時代の海外移住戦略

コメント

コメントする

目次