無料でサイトとDiscordBot構築してみた
はじめに
こんにちは、あずき(Azq)です。普段は、Webアプリ、Discord Bot、Windowsツール、ゲームなどを、自分で企画して作っています。
「個人でサイトやBotを作ると、サーバー代やドメイン代がかかりそう」と思ったことはありませんか?使うものを選べば、ほとんどお金をかけずに作れます。この記事では、私が使っている構成と手順を、同じものを作りたい人がそのまま真似できるように、コードつきで書きます。
この記事は技術の共有が中心で、自作ツールの紹介は、いちばん最後に少しだけ載せています。
- HTMLだけでサイトを書き、Cloudflare Pagesで公開する方法
- Xserverとバンドルカードで、独自ドメインを1年間無料で用意した話
- Oracle VPSにデータを保存する小さなAPIの作り方(一例)
- discord.pyでBotを作り、VPSで24時間動かす方法
全体構成
まず、役割ごとに置き場所を分けた全体の形を見てみます。
ブラウザ
│
├─ 静的なページ ──▶ Cloudflare Pages(HTMLを置くだけ)
│ └ 独自ドメイン(Xserver × バンドルカードで1年無料)
│
└─ データの読み書き ─▶ Oracle VPS(APIとデータ保存)
Discord ◀──▶ Discord Bot(Python / discord.py)
- サイト:CSS・JSなしのHTMLだけで書く
- アプリ:1つのHTMLファイルで完結させる
- 公開:Cloudflare Pages
- データ保存:Oracle VPS
- ドメイン:Xserverとバンドルカードで1年無料
- Bot:Python(discord.py)
ビルドツールやフレームワークは使わないので、壊れる場所も覚えることも減ります。
サイトをHTMLだけで書く
サイトは、CSS・JavaScriptを使わず、HTMLだけで書いています。意味のあるタグ(header、nav、main、article、footerなど)で構造を作れば、ブラウザの標準のスタイルだけでも十分に読めるページになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>サイト名</title>
<meta name="description" content="サイトの説明">
</head>
<body>
<header>
<h1>サイト名</h1>
<nav>
<a href="/">ホーム</a>
<a href="/blog/">ブログ</a>
</nav>
</header>
<main>
<article>
<h2>記事のタイトル</h2>
<p>本文</p>
</article>
</main>
<footer><small>© サイト名</small></footer>
</body>
</html>
ポイントは3つです。lang を指定すること。viewport を入れてスマホでも崩れないようにすること。title と description を、ページごとに書くことです(見た目を整えたくなったら、あとからCSSを足せます)。
データの読み書きをする「アプリ」にはJavaScriptが必要なので、HTML・CSS・JSを1つのファイルにまとめて、そのファイルだけで動くようにしています。ファイルを1つ置けば動くので、公開も更新も楽です。
Cloudflare Pagesで公開する
公開には Cloudflare Pages を使っています。静的なファイルを置くだけで公開できてビルドも要らず、方法は2つあります。
方法1:GitHubと連携する
- HTMLファイルをGitHubのリポジトリに置く
- CloudflareのダッシュボードでPagesのプロジェクトを作り、リポジトリを選ぶ
- ビルドコマンドは空のまま、出力ディレクトリはHTMLを置いた場所(ルートなら
/)にする - デプロイすると、
プロジェクト名.pages.devで公開される
以降は、git push するだけで更新されます。
方法2:コマンドで直接アップロードする
Gitを使わず、wranglerで直接上げる方法もあります。
npx wrangler pages deploy ./public --project-name=my-site
./public に公開したいHTMLを入れておけば、そのまま公開されます。
独自ドメインを1年無料で用意する
独自ドメインは、Xserver とバンドルカードを組み合わせて、1年間無料で用意しました。ドメインは有料のことが多いので、最初の1年を無料にできると、気軽に試せます。
Cloudflare Pagesに独自ドメインをつなぐ
- PagesのプロジェクトのCustom domainsから、使いたいドメインを追加する
- サブドメイン(例:
wwwやblog)なら、DNSにプロジェクト名.pages.devを向けるCNAMEレコードを追加する - ルートドメイン(
example.comそのもの)で使うなら、ネームサーバーをCloudflareに移す - 反映されるまで待つ(数分から、長いと数時間かかります)
ドメインを取ったサービスとは別のところにサイトを置く場合、このDNSの設定がいちばん大事です。
Oracle VPSにデータを保存する
HTMLだけのページではデータを保存できないので、保存が必要なものは Oracle の VPS に置いています。Oracle Cloudには「Always Free」という無料枠があり、条件を満たせば小さなサーバーを無料で動かせますが、内容や条件は変わることがあるので、公式の情報を確認してください。
ここからは、VPSに小さなAPIを置く方法の一例として、FastAPIとSQLiteで、メモを保存して読み出すだけのAPIを作ります。
1. APIを書く
main.pyimport sqlite3
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["https://example.com"], # 自分のサイトのURLだけ許可する
allow_methods=["GET", "POST"],
allow_headers=["*"],
)
db = sqlite3.connect("data.db", check_same_thread=False)
db.execute("create table if not exists notes (id integer primary key, body text)")
class Note(BaseModel):
body: str
@app.post("/notes")
def add_note(note: Note):
db.execute("insert into notes (body) values (?)", (note.body,))
db.commit()
return {"ok": True}
@app.get("/notes")
def list_notes():
rows = db.execute("select id, body from notes order by id desc limit 50").fetchall()
return [{"id": r[0], "body": r[1]} for r in rows]
2. 起動する
pip install fastapi uvicorn
uvicorn main:app --host 127.0.0.1 --port 8000
3. HTTPSで公開する
HTTPSのサイトからはHTTPのAPIを呼べないので、Caddyのようなリバースプロキシを前に置くと、証明書を自動で取得してくれて楽です。APIは api.example.com のようなサブドメインで公開します。
api.example.com {
reverse_proxy 127.0.0.1:8000
}
4. 1ファイルのアプリから呼ぶ
<script>
const API = "https://api.example.com";
async function addNote(body) {
await fetch(`${API}/notes`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ body }),
});
}
async function loadNotes() {
const res = await fetch(`${API}/notes`);
return res.json();
}
</script>
これで、「見た目はCloudflare Pages、データはVPS」という分け方ができます。
discord.pyでDiscord Botを作る
BotはPythonの discord.py で作っていて、Discord Developer Portalでトークンを発行できてライブラリもオープンソースなので、作るだけならお金はかかりません。
1. Botを登録する
- Discord Developer PortalでApplicationを作る
- Botを追加して、トークンを取得する
- OAuth2のURL作成で、
botとapplications.commandsを選んで招待URLを作る - 招待URLを開いて、自分のサーバーにBotを入れる
2. 最小のコード
pip install discord.py python-dotenv
bot.py
import os
import discord
from discord import app_commands
from dotenv import load_dotenv
load_dotenv() # .env から読み込む
intents = discord.Intents.default()
client = discord.Client(intents=intents)
tree = app_commands.CommandTree(client)
@tree.command(name="ping", description="生きているか確認します")
async def ping(interaction: discord.Interaction):
await interaction.response.send_message("pong")
@client.event
async def on_ready():
await tree.sync()
print(f"ログインしました: {client.user}")
client.run(os.environ["DISCORD_TOKEN"])
.env
DISCORD_TOKEN=ここにトークン
.env は .gitignore に入れて、GitHubに公開しないでください。もし漏らしてしまったら、Developer Portalですぐに再発行します。3. VPSで24時間動かす
Botを止めずに動かすには常時起動できる環境が必要で、VPSならsystemdに登録しておくと、落ちても自動で再起動してくれます。
/etc/systemd/system/mybot.service[Unit]
Description=Discord Bot
After=network-online.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/bot
ExecStart=/home/ubuntu/bot/venv/bin/python bot.py
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now mybot
sudo journalctl -u mybot -f # ログを見る
ユーザー名やパスは、自分の環境に合わせて変えてください。
ハマりどころ
- スラッシュコマンドがすぐ出ない:
tree.sync()でグローバルに登録すると、反映に時間がかかることがあるので、開発中は、特定のサーバーだけに同期すると早く確認できます。 - メッセージの内容が取れない:メッセージ本文を読むには、Developer PortalでMessage Content Intentを有効にして、コードでも指定する必要があります。
- VPSに外から繋がらない:OracleのVCN側のポート開放と、サーバー内のファイアウォールの、両方を確認します(片方だけだと繋がりません)。
- CORSエラーが出る:APIの
allow_originsに、サイトのURLが入っているか確認します。https://の有無や末尾のスラッシュも一致させます。 - 独自ドメインが反映されない:DNSの反映には時間がかかるので、CNAMEの向き先を間違えていないかも見ます。
まとめ
こういう工夫をして、サイトとBotを、ほとんどお金をかけずに作ることができました。
サイトはCSS・JSなしのHTMLだけで書いて、アプリは1つのHTMLファイルにまとめたので、ビルドもフレームワークも使わず、覚えることが少なくすぐ作り始められます。公開はCloudflare Pagesに置くだけで、更新も git push か1コマンドで済みます。
データが必要な部分だけをOracle VPSに分けたので、HTMLのページは軽いままで、VPSには小さなAPIを置いて、1ファイルのアプリから fetch で呼ぶ形にしました。独自ドメインはXserverとバンドルカードで1年無料にでき、BotはPythonとdiscord.pyで小さなコードから育てて、systemdで24時間動かしています。
特別な技術は使っていません。道具を絞ること、役割ごとに置き場所を分けること、無料枠やキャンペーンを調べて使うこと、小さく作って足していくこと、この4つを続けただけです。これから作る人は、HTMLを1枚公開するか、ping に答えるBotを動かすところから始めてみてください。
作ったもの
最後に、この構成で作ったものを少しだけ紹介するので、気になったものがあれば見てみてください。
AZQ BOTのコードはGitHubで公開していて、質問はサポートサーバーで受け付けています。AzqTrackerの更新情報はGitHubで確認できます(ウイルス対策ソフトに誤検知される場合がありますが、ウイルスは含まれていません)。そのほかの情報はX(@azky_yt)やYouTubeで発信しています。最後まで読んでくれて、ありがとうございました。