🫑tech.miyabitti

無料でDiscordBotを運用できる「Discord Hono」を使ってみた 【初学者向け】

無料でDiscordBotを運用できる「Discord Hono」を使ってみた 【初学者向け】

常時稼働は出来ませんが、Cloudflare WorkersでDiscordBotを運用できるライブラリ「Discord Hono」を紹介します。

目次

#はじめに

Discord Botを運用しようとすると、サーバーの用意をしなければならず、コスト面などで非常にハードルが高いと感じます。無料枠で運用することも可能ですが、どこまでのスケールが無料なのかや、自動スリープ対策等ハック的なことをしなければならなかったりと下調べも簡単ではありません。

そこで、Cloudflare Workersで動かせるDiscord Botライブラリである、Discord Honoを紹介します。

#従来のDiscord Botはどう動いているか

まず、一般的なDiscord Botがどのように動作しているかを簡単に説明します。

従来のBotはWebSocket1と呼ばれる仕組みを使って、Discordのサーバーと常時接続しています。ユーザーがメッセージを送ったり、コマンドを使ったりすると、その情報がリアルタイムでBotに届き、Botが反応します。

この方式だと、Botは24時間常にプログラムを起動し続けるサーバー2が必要です。これがコストや管理の手間がかかる原因です。

#サーバーレスとCloudflare Workers

#サーバーレスとは

サーバーレス3とは、「サーバーを自分で管理しない」仕組みのことです。サーバーが存在しないわけではなく、クラウドサービス側がサーバーを管理してくれます。プログラムは「リクエストが来たときだけ起動」し、処理が終わると停止します。そのため待機中のコストがかからず、スケーリングも自動で行われます。

#Cloudflare Workersとは

Cloudflare Workers4は、Cloudflareが提供するサーバーレス実行環境です。世界中に分散したエッジサーバー5上でコードが実行されるため、ユーザーの近くで高速に動作します。無料プランでは1日10万リクエストまで使用できます。

Discord HonoはこのCloudflare Workersで動作するDiscord Botライブラリです。WebSocketによる常時接続の代わりに、HTTP6を使ってDiscordからのイベントを受け取ります。

#できること・できないこと

サーバーレス型BotであるDiscord Honoと、従来のサーバー型Botではできることに違いがあります。

サーバー型BotDiscord Hono(サーバーレス)
スラッシュコマンドへの返答
ボタン・モーダル等のインタラクション
REST API7の利用
Cron8による定期実行
VCへの接続(音楽Botなど)
メッセージ監視・自動返答
無料でダウンタイムなし❌(対策が必要)
大規模スケーリングコストがかかりやすい

最大のデメリットは、WebSocketを使った常時接続が必要な機能が使えないことです。具体的には以下ができません

  • ボイスチャンネルへの接続(音楽Bot、会話Botなど)
  • メッセージの監視・自動返答(特定ワードへの反応など)
  • Botのステータス表示のリアルタイム更新

逆に、スラッシュコマンドへの応答・ボタンやモーダルなどのインタラクション・定期実行が中心のBotであれば、Discord Honoで十分実用的に運用できます。

💡 どんなBotに向いている?
「ユーザーがコマンドを打ったら何かしてくれる」という用途がメインのBotに最適です。情報検索・翻訳・ランダム抽選・ゲームサポートなどが挙げられます。

上記のことがしたい場合は素直にサーバーを借りるのが正解です。

#前提

本記事を進めるに当たって、以下のことが必要です。

  1. Discordのアカウントがあること
  2. Cloudflareのアカウントがあること
  3. bun9がインストールされていること - bunでなくても、node(npm/pnpm) や deno等でも問題ありません。
  4. VSCodeがインストールされていること - エディタであれば何でも良いです。

#事前準備:Developer Portalでの設定

Discord Botを作るには、まずDiscord Developer Portalでアプリケーションを作成し、トークン10などを取得する必要があります。

#1. アプリケーションの作成

  1. Discord Developer Portal にアクセスする
  2. 右上の「New Application」をクリックする
  3. Botの名前を入力して「Create」をクリックする

新しいアプリケーションの作成

#2. 各種キーの取得

アプリケーション作成後、左メニューの「General Information」を開き、以下の2つを控えておきます。

  • APPLICATION ID:BotのアプリケーションID
  • PUBLIC KEY:リクエストの署名検証11に使用するキー

#3. Botトークンの発行

  1. 左メニューの「Bot」タブを開く
  2. Reset Token」をクリックしてトークンを発行する
  3. 表示されたトークンをコピーして控えておく

⚠️ 注意
トークンは一度しか表示されません。ページを閉じた後は再確認できないので、必ずコピーして安全な場所に保存してください。

#テスト用Discordサーバーの準備

事前にBotをテストするサーバーを用意してください。そして、そのサーバーのIDをコピーします。

サーバーIDは、ブラウザであればdiscord.com/channels/[server-id]/[channel-id] の形式なので、server-idの部分をコピーしてください。

デスクトップアプリであれば、設定画面から、開発者モードをONにしたうえで、サーバー設定などを確認する場所の一番下にサーバーIDをコピーがあります。

サーバーIDのコピー方法

#プロジェクトのセットアップ

#Cloudflare Workersプロジェクトの作成

Terminal window
bunx create-cloudflare@latest discord-hono-bot
cd discord-hono-bot

いくつか質問されます。以下のように選択してください。

  • What would you like to start with?Hello World example
  • Which template would you like to use?Worker only
  • Which language do you want to use?TypeScript
  • Do you want to use git for version control?Yes(任意)
  • Do you want to deploy your application?No(後で手動でデプロイします)

続いて、discord-hono と、DiscordのAPIの型を提供してくれるライブラリをインストールします。

Terminal window
bun add discord-hono
bun add -D discord-api-types

#環境変数の設定

プロジェクトルートに .env ファイルを作成し、Developer Portalで控えた値を設定します。このファイルはローカルでのコマンド登録スクリプト実行時に使用します。

DISCORD_APPLICATION_ID=your_application_id
DISCORD_PUBLIC_KEY=your_public_key
DISCORD_TOKEN=your_bot_token
DISCORD_TEST_GUILD_ID=your_test_server_id

.gitignore.env が含まれているか確認し、含まれていない場合は追記してください。

#wrangler.jsonc確認・編集

wrangler.jsonc12を開き、以下のようになっているか確認します。

{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "discord-hono-bot",
"main": "src/index.ts",
"compatibility_date": "2026-04-15", // 今日の日付でおk!
"observability": {
"enabled": true
},
"upload_source_maps": true,
"compatibility_flags": [
"nodejs_compat"
]
}

#package.jsonにスクリプトを追加する

package.jsonscripts セクションを以下のように編集します。

{
"scripts": {
"dev": "wrangler dev",
"deploy": "wrangler deploy",
"register": "bun --env-file=.env src/register.ts"
}
}

#Botを実装する

#src/index.ts を作成する

src/index.ts がBotのメインハンドラーです。Cloudflare Workersへのリクエストをここで受け取り、コマンドに応じて処理します。まずは /ping に「Pong! 🏓」と返すだけのシンプルな実装から始めます。

src/index.ts
import { DiscordHono } from 'discord-hono'
// Cloudflare Workersの環境変数の型定義
type Env = {
Bindings: {
DISCORD_TOKEN: string
DISCORD_PUBLIC_KEY: string
DISCORD_APPLICATION_ID: string
}
}
const app = new DiscordHono<Env>()
.command('ping', (c) => c.res('Pong! 🏓'))
export default app

c.res() はコマンドへの返答メソッドです。文字列を渡すと、その内容がDiscordにメッセージとして送信されます。

名前の通り、かなりhonoに近い書き方なので、honoを知っていれば学習コストも低いでしょう。

#src/register.ts を作成する

Discordのスラッシュコマンドは、Discord APIに事前に登録しておく必要があります13src/register.ts として登録用スクリプトを作成します。

import { Command, register } from 'discord-hono'
const commands = [
new Command('ping', 'Pongと返答します'),
]
register(
commands,
process.env.DISCORD_APPLICATION_ID,
process.env.DISCORD_TOKEN,
)

#コマンドの登録とデプロイ

#コマンドをDiscordに登録する

Terminal window
bun run register

コマンドの登録はDiscord APIへのリクエストです。登録自体はすぐ完了しますが、Discordのクライアントに反映されるまで最大1時間かかる場合があります。

#本番環境の環境変数を設定する

Cloudflare Workersに .env ファイルはそのまま使えません。本番用のシークレット14は、wrangler secret put コマンドで設定します。

Terminal window
bunx wrangler secret put DISCORD_APPLICATION_ID
bunx wrangler secret put DISCORD_PUBLIC_KEY
bunx wrangler secret put DISCORD_TOKEN

それぞれのコマンドを実行すると、対話的に値の入力を求められます。.env に記載した対応する値を入力してください。

#Cloudflare Workersへデプロイする

Terminal window
bun run deploy

デプロイ15が完了すると、以下のようなURLが発行されます。

https://discord-hono-bot.your-subdomain.workers.dev

#INTERACTIONS ENDPOINT URLを設定する

Discordはコマンドが実行されると、事前に登録したURL(エンドポイント16)にHTTPリクエストを送信します。このURLをDeveloper Portalに設定します。

  1. Discord Developer Portalの「General Information」タブを開く
  2. INTERACTIONS ENDPOINT URL」にデプロイで発行されたWorkerのURLを入力する
  3. Save Changes」をクリックする

Discordがエンドポイントの疎通確認を行うため、この時点でWorkerが正常に動いていることが重要です。保存に成功すれば、BotがDiscordからのインタラクションを受け取れる状態になります。

#BotをサーバーへInviteする

  1. Discord Developer Portalの「OAuth2」タブを開く
  2. OAuth2 URL Generator」を選択する
  3. SCOPESbotapplications.commands にチェックを入れる
  4. 生成されたURLをブラウザで開き、招待するサーバーを選択する

招待後、Discordのチャットで /ping と入力すると「Pong! 🏓」と返ってくるはずです 🎉

#実践:ボタンインタラクション付きのダイスコマンド

Discord Honoはボタン等のコンポーネントインタラクション17にも対応しています。ここでは、「もう一度振る」ボタン付きのダイスロールコマンドを実装してみます。ゲームサーバーなどで実用的に活用できるコマンドです。

#register.ts にコマンドを追加する

import { Command, register } from 'discord-hono'
const commands = [
new Command('ping', 'Pongと返答します'),
new Command('dice', 'サイコロを振ります'), // 追加
]
register(
commands,
process.env.DISCORD_APPLICATION_ID,
process.env.DISCORD_TOKEN,
)

#index.ts を更新する

src/index.ts をボタンインタラクションに対応するよう更新します。

import { DiscordHono, Components, Button } from 'discord-hono'
type Env = {
Bindings: {
DISCORD_TOKEN: string
DISCORD_PUBLIC_KEY: string
DISCORD_APPLICATION_ID: string
}
}
// 1〜6のランダムな整数を返す
const rollDice = () => Math.floor(Math.random() * 6) + 1
// ダイス結果のメッセージ(ボタン付き)を生成する関数
const diceResponse = (result: number) => ({
content: `🎲 **${result}** が出ました!`,
components: new Components().row(
new Button('reroll', 'もう一度振る 🎲'),
),
})
const app = new DiscordHono<Env>()
// /ping コマンド
.command('ping', (c) => c.res('Pong! 🏓'))
// /dice コマンド:初回はコマンドとして返答
.command('dice', (c) => c.res(diceResponse(rollDice())))
// 「もう一度振る」ボタンが押されたとき:メッセージを更新
.component('reroll', (c) => c.resUpdate(diceResponse(rollDice())))
export default app

実装のポイントは2つあります。

  1. .component() の第1引数('reroll')を new Button() の第1引数(カスタムID)と一致させることで、ボタン押下時のハンドラーを紐付けています
  2. c.resUpdate() を使うことで、ボタンを押したとき元のメッセージを新しい結果で上書きできます。c.res() だと新しいメッセージが追加されてしまうため、resUpdate を使うと「結果が更新される」自然なUXを実現できます

#再登録してデプロイする

Terminal window
bun run register
bun run deploy

/dice を実行するとサイコロが振られ、「もう一度振る 🎲」ボタンを押すたびに結果が更新されます。

#おわりに

Discord Honoを使うことで、サーバーの管理不要・無料ダウンタイムなしでDiscord Botを運用できました。常時接続が不要なBotであれば、Discord Honoは非常に優れた選択肢です。

今回紹介したボタン以外にも、モーダル(入力フォーム)・セレクトメニュー・オートコンプリート・Cronトリガーによる定期実行など豊富な機能が揃っています。当然、Cloudflareエコシステム(D1,R2,KV等)もそのまま使用できるので、実践的なアプリケーションも作成することも可能です。ぜひ公式ドキュメントも参照しながら、機能を拡張してみてください。

間違っている箇所があればXのDMまでお知らせください!即座に修正いたします。

#Footnotes

  1. WebSocketとは、サーバーとクライアントが一度接続を確立したあと、どちら側からでも好きなタイミングでデータを送受信できる通信方式です。通常のHTTPが「リクエストしたら返事が来る」一方通行の会話なのに対し、WebSocketは「いつでも話しかけられる」電話のようなイメージです。チャットアプリやリアルタイムゲームで広く使われています。

  2. ここでのサーバーとは、プログラムを常時動かし続けるコンピューターのことです。VPSやクラウドVM(AWS EC2、Google Compute Engineなど)が該当します。無料枠があるサービスも存在しますが、自動スリープや時間制限があることが多いです。

  3. サーバーレスとは、開発者がサーバーの管理・調達を気にせず、コードの実行だけに集中できるクラウドの仕組みです。「関数」としてコードを登録しておくと、リクエストが来たときだけ自動で起動します。AWS LambdaやCloudflare Workersが代表例です。

  4. Cloudflare Workersは、Cloudflareが提供するサーバーレスプラットフォームです。無料プランでは1日10万リクエストまで利用できます。Botのコマンド応答程度であれば無料枠で十分運用できます。

  5. エッジサーバーとは、ユーザーの地理的に近い場所に配置されたサーバーのことです。遠くの中央サーバーと通信するより遅延が少なく、高速なレスポンスが実現できます。

  6. HTTP(HyperText Transfer Protocol) とは、WebブラウザがWebサーバーとデータをやり取りするための基本的な通信プロトコルです。「リクエスト(お願い)」を送ると「レスポンス(返答)」が返ってきます。

  7. REST APIとは、HTTPを使ってデータのやり取りを行うWebサービスの設計方式のことです。Discord APIもREST APIとして提供されており、メッセージの送信やユーザー情報の取得などをHTTPリクエストで行えます。

  8. Cronとは、指定した時刻や間隔でプログラムを自動実行する仕組みです。「毎日9時に天気予報を送信する」といった定期実行Botに活用できます。

  9. Bunとは、Node.jsの代替として登場した高速なJavaScript/TypeScriptランタイムです。パッケージのインストール(npm install 相当)も bun add で行えます。TypeScriptをそのまま実行できる点が特徴で、別途コンパイル用ツールは不要です。

  10. トークンとは、BotがどのアカウントとしてDiscordで動作するかを認証するための「合言葉」のようなものです。これが流出すると第三者がBotを乗っ取れてしまうため、厳重に管理する必要があります。

  11. 署名検証とは、Discordから届いたリクエストが本物かどうかを確認する仕組みです。悪意のある第三者が偽のリクエストを送り込むのを防ぎます。Discord Honoが内部で自動的に処理してくれるため、開発者が特別なコードを書く必要はありません。

  12. wrangler.jsoncは、Cloudflare Workersプロジェクトの設定ファイルです。プロジェクト名や使用するファイルのパスなどを定義します。コメント付きJSON形式で記述します。

  13. Discord Botのスラッシュコマンドは、Discordのサーバーに「このコマンドが使えますよ」と申告することで、ユーザーが / を入力したときの補完リストに表示されるようになります。コードを変更しただけではコマンドは増えないため、この登録スクリプトの実行が必要です。

  14. Cloudflare Workersにおけるシークレットとは、本番環境でのみ使用する暗号化された環境変数のことです。コードとは分離して管理され、Cloudflareのダッシュボードから管理できますが、値そのものは暗号化されて保護されています。

  15. デプロイとは、作成したプログラムを実際にサーバー(今回はCloudflare Workers)に配置して、外部からアクセスできる状態にすることです。

  16. エンドポイントとは、APIやWebサービスへのアクセス先となるURLのことです。ここでは「DiscordがBotにリクエストを送る宛先」を意味します。

  17. コンポーネントインタラクションとは、Discordのメッセージに埋め込まれたボタン・セレクトメニュー・モーダル(入力フォーム)などのUI要素をユーザーが操作したときに発生するイベントのことです。