Cloudflare Workers の無料枠と LINE Messaging API を組み合わせると、サーバー代ゼロで LINE Bot を動かせます。この記事では「アカウント作成→コーディング→デプロイ→LINE接続」までを順を追って説明します。Node.js の基本操作ができれば、プログラミング歴が浅くても手順通りに動くボットを完成させられます。
仕組みの全体像(図解)
下の図が、これから作る LINE Bot の全体の流れです。ユーザーの発言が LINE から Cloudflare Worker に渡り、署名を確認してから返信が返ります。
flowchart LR U[ユーザー LINE] -->|メッセージ| LP[LINE Platform] LP -->|Webhook POST| CW[Cloudflare Worker] CW -->|署名検証 X-Line-Signature| CW CW -->|Reply API で返信| LP LP -->|返信が届く| U
前提知識と用意するもの
| 必要なもの | 補足 |
|---|---|
| Node.js 18 以上 | nodejs.org からインストール |
| npm(Node.js に同梱) | バージョン確認: npm -v |
| Cloudflare アカウント(無料) | クレジットカード不要 |
| LINE Developers アカウント(無料) | LINE アプリのアカウントで登録可 |
| ターミナル操作の最低限の知識 | コマンドを貼って実行できれば OK |
Cloudflare Workers の無料枠まとめ
- リクエスト数: 10万回/日
- CPU 時間: リクエストあたり最大 10ms(実際の I/O 待ち時間はカウント外)
- カスタムドメインなしでも
*.workers.devの HTTPS URL が自動付与される
LINE Messaging API の無料プラン(フリープラン)では「返信メッセージ(Reply)」は無制限で送れます。「プッシュメッセージ(Push)」は月 200 通まで無料です。エコーボット(おうむ返し)や質問応答系のボットなら、ほぼ無料の範囲内で運用できます。
LINE Developers でチャンネルを作る
1. LINE Developers コンソールにログイン
LINE Developers にアクセスし、LINEアカウントでログインします。
2. プロバイダーを作成する
初回ログイン時に「プロバイダーを作成」を求められます。プロバイダー名は自分のサービス名や屋号など、なんでも構いません(後から変更可)。
3. チャンネルを作成する(Messaging API)
- プロバイダーのページで「チャンネルを作成」をクリック
- 「Messaging API」を選択(LINE Login や CLOVA とは別のものです)
- 必要事項を入力して作成完了
4. 必要な認証情報を控える
チャンネル作成後、以下の2つの値を後で使うのでメモしておきます。
| 項目 | 場所 |
|---|---|
| チャンネルシークレット | チャンネル基本設定タブ |
| チャンネルアクセストークン(長期) | Messaging API 設定タブ → 一番下の「チャンネルアクセストークン」欄で「発行」ボタンを押す |
注意: チャンネルアクセストークンは「発行」を押さないと表示されません。発行後はすぐメモしてください。
Cloudflare Workers のセットアップ
1. Wrangler をインストールしてログインする
npm install -g wrangler
wrangler login
wrangler login を実行するとブラウザが開き、Cloudflare の認証ページへ誘導されます。ログインして認可を完了させてください。
2. プロジェクトを作成する
npm create cloudflare@latest line-bot
対話式の質問が続きます。以下のように答えてください。
? What would you like to start with?
→ Hello World example
? Which template would you like to use?
→ Hello World Worker
? Which language do you want to use?
→ JavaScript
? Do you want to use git for version control?
→ Yes(任意)
? Do you want to deploy your application?
→ No(後でデプロイします)
作成完了後、プロジェクトフォルダに移動します。
cd line-bot
3. シークレット(秘密情報)を環境変数として登録する
ソースコードにチャンネルシークレットやアクセストークンを直書きしてはいけません。Wrangler のシークレット機能を使います。
wrangler secret put LINE_CHANNEL_SECRET
# → プロンプトが出るので、チャンネルシークレットの値を貼り付けてEnter
wrangler secret put LINE_CHANNEL_ACCESS_TOKEN
# → チャンネルアクセストークンの値を貼り付けてEnter
Webhook ハンドラーのコードを書く
src/index.js を以下の内容で丸ごと置き換えます。
export default {
async fetch(request, env) {
// LINE は POST だけを送ってくる。それ以外は無視
if (request.method !== 'POST') {
return new Response('Method Not Allowed', { status: 405 });
}
const bodyText = await request.text();
const signature = request.headers.get('X-Line-Signature');
// 署名検証(必須。これを省くと不正リクエストを受け入れてしまう)
const isValid = await verifySignature(bodyText, signature, env.LINE_CHANNEL_SECRET);
if (!isValid) {
return new Response('Unauthorized', { status: 401 });
}
const { events } = JSON.parse(bodyText);
// イベントを順番に処理(await を忘れずに)
for (const event of events) {
if (event.type === 'message' && event.message.type === 'text') {
await replyText(
event.replyToken,
`受け取ったよ:${event.message.text}`,
env.LINE_CHANNEL_ACCESS_TOKEN
);
}
}
// LINE のサーバーへは必ず 200 OK を返す
return new Response('OK', { status: 200 });
},
};
// HMAC-SHA256 で署名を検証する(Web Crypto API を使用)
async function verifySignature(body, signature, channelSecret) {
if (!signature) return false;
const encoder = new TextEncoder();
const key = await crypto.subtle.importKey(
'raw',
encoder.encode(channelSecret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
const signBuffer = await crypto.subtle.sign('HMAC', key, encoder.encode(body));
const expectedSignature = btoa(String.fromCharCode(...new Uint8Array(signBuffer)));
return signature === expectedSignature;
}
// テキストメッセージを返信する
async function replyText(replyToken, text, channelAccessToken) {
const res = await fetch('https://api.line.me/v2/bot/message/reply', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${channelAccessToken}`,
},
body: JSON.stringify({
replyToken,
messages: [{ type: 'text', text }],
}),
});
// デバッグ用(本番ではコメントアウト推奨)
if (!res.ok) {
const err = await res.text();
console.error('LINE API error:', err);
}
}
コードのポイント
verifySignature関数はCloudflare Workers が標準で持つWeb Crypto APIを使っています。外部ライブラリが不要なので、依存関係が増えません。- 署名検証を省略すると、誰でも偽のリクエストを送れる状態になります。必ず実装してください。
- LINE は webhook に対して 1 秒以内に
200 OKを返すことを求めています。重い処理(AI API 呼び出しなど)で遅延する場合は、waitUntilを使って非同期化する構成が必要です(後述)。
デプロイして LINE に接続する
1. Cloudflare Workers へデプロイ
wrangler deploy
成功すると末尾に以下のような URL が表示されます。
Published line-bot (1.23 sec)
https://line-bot.あなたのサブドメイン.workers.dev
この URL をコピーしておきます。
2. LINE の Webhook URL を設定する
- LINE Developers コンソールを開く
- 作成したチャンネル → 「Messaging API 設定」タブを開く
- 「Webhook URL」欄にデプロイした URL を貼り付ける(末尾に
/は不要) - 「検証」ボタンをクリック → 「成功」と表示されれば OK
- 「Webhookの利用」をオンにする(デフォルトはオフです)
注意: 「Webhookの利用」をオンにしないとメッセージが届きません。見落としがちなポイントです。
3. 動作確認
LINE アプリで自分のボットアカウントを友だち追加して、テキストメッセージを送ってみてください。「受け取ったよ:〇〇」と返ってきたら成功です。
友だち追加用 QR コードは LINE Developers コンソールの「Messaging API 設定」タブで確認できます。
AI(OpenAI / Claude)と繋げる場合の追加手順
エコーボットができたら、次のステップとして AI API と連携する構成が一般的です。処理時間が長くなるため、waitUntil パターンが必要です。
export default {
async fetch(request, env, ctx) {
if (request.method !== 'POST') {
return new Response('Method Not Allowed', { status: 405 });
}
const bodyText = await request.text();
const signature = request.headers.get('X-Line-Signature');
if (!await verifySignature(bodyText, signature, env.LINE_CHANNEL_SECRET)) {
return new Response('Unauthorized', { status: 401 });
}
const { events } = JSON.parse(bodyText);
// LINE へ先に 200 を返し、AI 処理はバックグラウンドで動かす
ctx.waitUntil(handleEvents(events, env));
return new Response('OK', { status: 200 });
},
};
async function handleEvents(events, env) {
for (const event of events) {
if (event.type === 'message' && event.message.type === 'text') {
const aiReply = await callAI(event.message.text, env);
await replyText(event.replyToken, aiReply, env.LINE_CHANNEL_ACCESS_TOKEN);
}
}
}
async function callAI(userMessage, env) {
// Anthropic Claude を使う例(env.ANTHROPIC_API_KEY を wrangler secret put で登録しておく)
const res = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': env.ANTHROPIC_API_KEY,
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: 'claude-haiku-4-5-20251001',
max_tokens: 300,
messages: [{ role: 'user', content: userMessage }],
}),
});
const data = await res.json();
return data.content?.[0]?.text ?? '応答できませんでした';
}
AI API キーも忘れずに wrangler secret put で登録してください。
よくあるエラーと対処
エラー1: 「検証」ボタンを押すと「失敗」と表示される
原因の確認順序
- URL の末尾に余分なスラッシュ(
/)が入っていないか確認する wrangler deployが正常に完了しているか確認する(URL が表示されたかどうか)- Workers のコードが
200 OKを返しているか確認する
LINE の「検証」リクエストはevents: [](空配列)を送ってきます。コードがeventsを処理する前に200 OKを返す構造になっていれば問題ありません。上記のサンプルコードはその構造になっています。
エラー2: メッセージを送っても返信が来ない
チェックリスト
- [ ] LINE Developers コンソールで「Webhookの利用」がオンになっているか
- [ ]
wrangler secret putでシークレットを正しく登録したか(タイポがないか) - [ ]
wrangler deployを再実行したか(シークレット追加後は再デプロイ不要だが、コード変更後は必要)
Cloudflare Workers のログをリアルタイムで確認するには以下のコマンドが便利です。
wrangler tail
エラーメッセージが表示されれば、原因特定が格段に楽になります。
エラー3: 署名検証が通らない(401 Unauthorized ばかり)
よくある原因
LINE_CHANNEL_SECRETに誤った値を登録している(チャンネルアクセストークンと取り違えている場合など)wrangler secret put実行後にスペースや改行が混入している
対処
# 一度削除して入れ直す
wrangler secret delete LINE_CHANNEL_SECRET
wrangler secret put LINE_CHANNEL_SECRET
値を貼り付けるとき、末尾に改行が入らないよう注意してください。
エラー4: wrangler deploy で "Missing entry-point" エラー
原因: wrangler.toml の main が src/index.js を指していない、またはファイルが存在しない。
# wrangler.toml を確認
name = "line-bot"
main = "src/index.js" # ← ここが正しいか確認
compatibility_date = "2024-09-23"
src/index.js が存在するかも確認してください(ls src/)。
エラー5: AI 返信が遅くて LINE 側でタイムアウトする
LINE は webhook に対して約 1 秒以内の 200 応答を要求します。AI API の呼び出しは数秒かかるため、AI 処理と 200 応答を切り離す必要があります。
上記の「AI と繋げる場合」のコードで示した ctx.waitUntil(handleEvents(...)) パターンがその解決策です。waitUntil に渡した Promise は、レスポンス送信後もバックグラウンドで実行され続けます。
まとめと次の一歩
今回やったこと
- LINE Developers でチャンネルを作成し、認証情報を取得
- Cloudflare Workers プロジェクトを作成し、シークレットを登録
- HMAC-SHA256 署名検証付きの Webhook ハンドラーをコーディング
wrangler deployでデプロイし、LINE に Webhook URL を登録- エコーボットとして動作確認
これで「サーバー代ゼロ・HTTPS 自動対応」の LINE Bot の土台が完成しました。
次にできること
- AI 応答ボット: 上記の
callAI関数を組み込んで質問応答ボットにする - Cloudflare KV でユーザー状態を保存: 会話の文脈を持たせたい場合は Workers KV(無料枠あり)を使う
- 画像・スタンプへの対応:
event.message.typeがimageやstickerの場合の分岐を追加する - カスタムドメインを設定: Cloudflare の DNS 管理下のドメインなら無料で Workers に紐付けられる
詳細な API リファレンスは LINE Messaging API ドキュメント と Cloudflare Workers ドキュメント を参照してください。公式ドキュメントが最も信頼できる情報源です。