AIで競馬予測サービスを作った話——iOSアプリからWebサービス化、Stripe課金まで全部やった

ガジェット

こんにちは、nodenceです。

競馬の予測AIをずっと個人で開発していたのですが、このたびWebサービスとして一般公開しました。

今日はその開発の全過程を振り返ります。「個人開発で課金サービスを作りたい」「自宅サーバーでWebサービスを運営したい」という方の参考になれば嬉しいです。

▼ サービスURL:https://keiba.nodence.jp


そもそも何を作ったか

「競馬AI予測」というWebサービスです。

機械学習(LightGBM)が中央競馬の全レースを自動分析し、各馬のAIスコア(100点満点)◎本命・○対抗・▲単穴の推奨馬印を提供します。月額2,980円のサブスクリプション制で、いつでも解約できます。

主な機能:

  • 中央競馬の全レースに対応
  • 当日朝から予測を提供
  • AIスコアで各馬を数値化
  • 複勝オッズの最小〜最大値を表示
  • スマートフォン・PCどちらからでも利用可能

開発の経緯——なぜWebサービスにしたのか

もともと競馬が好きで、Jupyter Notebookで予測モデルを作っていました。LightGBMに馬の過去成績・騎手・血統・馬体重・オッズなど多数の特徴量を学習させた独自モデルです。

最初はiOSアプリとして自分だけで使っていました。スクレイピングでnetkeiba.comからデータを取得し、FastAPI(Python)でAPIサーバーを立てて、iPhoneから予測結果を閲覧する仕組みです。

「これを有料サービスにしよう」と考えたとき、最初に思いつくのはApp Storeでの公開です。しかしAppleは課金収益の30%を手数料として持っていきます。月額2,980円なら約900円がAppleの取り分になる計算。

「それならWebサービスにしてStripeで決済しよう」というのが今回の動機でした。Stripeの手数料は3.6%。900円と107円、その差は歴然です。


技術スタック

新たにクラウドサーバーを借りるのではなく、既存の自宅Windows PCをそのまま活用しました。もともとWordPressブログ(nodence.jp)をApacheで運営しており、そこにサブドメイン(keiba.nodence.jp)を追加する形で構築しました。

インフラ

  • サーバー:自宅Windows PC(常時起動)
  • Webサーバー:Apache(既存)
  • SSL証明書:Let’s Encrypt(Win-ACME)

Webアプリ(新規)

  • バックエンド:FastAPI(Python 3.10)
  • データベース:SQLite + SQLAlchemy
  • 認証:JWT(HS256、7日間有効)
  • パスワード:bcrypt(ハッシュ化)
  • 決済:Stripe Checkout + Subscription + Webhook
  • フロントエンド:バニラJS + Tailwind CSS CDN
  • メール送信:Gmail SMTP(アプリパスワード)
  • セキュリティ:slowapi(レートリミット)

既存API(流用)

  • FastAPI(Python)、port 8000
  • Selenium + BeautifulSoup(スクレイピング)
  • LightGBMモデル

既存のiOS向けAPI(port 8000)はそのまま残し、新しいWebアプリ(port 8001)を追加。Apacheがサブドメインごとに振り分ける構成にしました。


実装した機能一覧

認証系

  • 新規登録(メールアドレス + パスワード)
  • ログイン / ログアウト
  • パスワード強度チェック(8文字以上 + 数字 + 記号)
  • メール認証(登録時に確認メールを送信)
  • パスワードリセット(メールでリセットリンクを送信)

課金系

  • Stripe Checkoutで月額サブスクリプション
  • Stripeカスタマーポータルで解約・支払い管理
  • WebhookでDB自動更新
  • メール認証なしでは課金不可

予測系

  • 当日のレース一覧取得
  • 非同期バックグラウンドでスクレイピング→予測
  • AIスコア・馬印・複勝オッズの表示

セキュリティ

  • レートリミット(登録:5回/分、ログイン:10回/分)
  • HTTPS強制
  • カード情報は自サーバーに保存しない(Stripe管理)

ハマったこと・解決したこと

個人開発あるあるですが、想定外のトラブルが山ほどありました。

① bcryptのバージョン問題

passlib経由でbcryptを使おうとしたら module 'bcrypt' has no attribute '__about__' エラー。bcrypt 4.x系ではpasslibが対応していないのが原因でした。passlibをやめてbcryptを直接使うことで解決。

import bcrypt
bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()

② ApacheのVirtualHost問題

keiba.nodence.jpのVirtualHostを追加したら、なぜかWordPressが {"detail":"Not Found"} を返すように。keiba用のVirtualHostがデフォルトになってしまい、WordPress向けHTTPSリクエストまで横取りしていました。

httpd-ssl.confにnodence.jp用の明示的なVirtualHostを追加して解決。VirtualHostの順番と明示的なServerNameが重要でした。

③ ローカルネットワークからアクセスできない

自宅のMacから https://keiba.nodence.jp にアクセスすると「応答時間が長すぎます」。原因はルーターがヘアピンNAT(ループバック)に非対応だったこと。MacのHostsファイルに 192.168.1.101 keiba.nodence.jp を追記して解決。

④ SSL証明書がサブドメインに対応していない

既存のnodence.jp証明書はkeibaサブドメインをカバーしていませんでした。Win-ACMEでDNSチャレンジを使い、お名前.comにTXTレコードを追加してkeiba.nodence.jp専用の証明書を取得しました。証明書の自動更新もタスクスケジューラに登録済みです。

⑤ ZohoメールのSMTPリレー制限

メール認証機能を実装してZohoのSMTPを使おうとしたら 553 Sender is not allowed to relay emails エラー。Zohoのリレー設定が見つからず、最終的にGmail SMTPに切り替えました。Gmailのアプリパスワードを使えばすんなり動きました。

ちなみにZohoのSMTPサーバーはsmtp.zoho.comではなくsmtp.zoho.jpでした(日本のアカウント)。smtp.zoho.comだと認証エラーになります。

⑥ 日付フォーマットの不一致

フロントエンドのdateピッカーが 2026-05-10 形式(ISO)で日付を送るのに、スクレイパーが 2026/05/10 形式しか受け付けない問題。スクレイパー側で両フォーマットに対応させて解決しました。

⑦ PythonのパスがWindowsで見つからない

where python コマンドを実行しても何も返ってこない。PythonがMicrosoft Storeのエイリアスとして登録されていたためでした。python -c "import sys; print(sys.executable)" で実際のパスを確認できました。


セキュリティ対策について

個人情報(メールアドレス)と課金情報を扱うので、セキュリティには特にこだわりました。

認証・暗号化

  • パスワードはbcryptでハッシュ化(平文は一切保存しない)
  • JWTトークン(HS256、7日間有効)
  • パスワード強度チェック(8文字以上 + 数字 + 記号必須)

不正アクセス対策

  • レートリミット(slowapi)でブルートフォース攻撃を防止
  • メール認証でなりすまし登録を防止
  • パスワードリセットトークンは1時間で失効

通信・決済

  • HTTPS強制(Let’s Encrypt、自動更新)
  • カード情報はStripeが管理(PCI DSS準拠)
  • 自サーバーにはカード情報を一切保存しない

インフラ構成(最終形)

[ユーザー(ブラウザ)]
    ↓ HTTPS
[Apache on Windows PC]
    ├─ nodence.jp      → WordPress(既存)
    └─ keiba.nodence.jp → FastAPI port 8001(新規)
                              ↓ HTTP localhost
                         競馬AI API port 8000(既存)
                              ↓ スクレイピング
                         netkeiba.com
                              ↓ 予測
                         LightGBMモデル

Apacheがリバースプロキシとして機能し、サブドメインごとにWordPressとFastAPIを振り分けています。WordPressとWebアプリが同一PCで共存できるのがこの構成の利点です。


費用について

月額のランニングコスト:

  • サーバー代:0円(自宅PC)
  • ドメイン代:約1,500円/年(お名前.com)
  • SSL証明書:0円(Let’s Encrypt)
  • Stripe手数料:3.6%(決済時のみ)
  • Gmail SMTP:0円

クラウドサービスを使わないので、月額固定費はほぼゼロです。ユーザーが増えればStripeの手数料が増えますが、それは売上に比例するので問題なし。

自宅PCを使うデメリットとしては停電・故障リスクがありますが、個人の副業サービスとしては十分なレベルと判断しました。


振り返り・感想

今回の開発で一番大変だったのは、既存のWordPress環境を壊さずにApacheのVirtualHost設定を変更することでした。SSLやサブドメインの設定は思った以上に奥が深く、何度もWordPressが壊れては直すを繰り返しました。

逆に想定より簡単だったのはStripeの実装です。Stripe Checkout + Webhookの組み合わせは公式ドキュメントが充実しており、セキュアな決済を短時間で実装できました。カード情報を自サーバーで一切扱わないので、セキュリティリスクも最小限です。

機械学習モデル自体は以前から作っていたものを流用しているので、今回の開発の本質は「AIモデルをSaaSとして提供するインフラを作ること」でした。

「AIは作れるけどWebサービス化のやり方がわからない」という方は多いと思います。FastAPI + Stripe + Apacheの組み合わせは、既存の開発環境を活かしながらWebサービス化するうえでとても有効でした。


おわりに

競馬AI予測、ぜひ使ってみてください。

無料登録してメール認証を完了すると、月額プランに加入できます。当日の全レース予測をAIスコアと馬印で確認できます。

サービスURL:https://keiba.nodence.jp

月額2,980円(税込)・いつでも解約可能

ご意見・ご要望はこちら:nodence@nodence.jp

※ 本サービスはAIによる予測情報の提供を目的としています。馬券購入・投資を推奨するものではありません。

タイトルとURLをコピーしました