なんやかんやあって個人開発アプリを自宅サーバーで運用してみようとなり色々してた時につまづいたことをまとめました。もはやこの記事は自分用。くっ、いい記事が書きたい...というね。
1. 全体構成の違い
開発 (docker-compose.yml) と本番 (docker-compose.prod.yml) の目的が逆方向で設計されていたため、両者の差分がそのままトラブルの原因になった。prodとか初めて触ったンゴ。
開発環境の特徴
- ホットリロード前提
→frontend/srcをマウント。npm run devで反映。 -
.envをそのまま読み込む - MongoDB をホスト公開(
27017:27017) - Redis/Mongo/Webhook まわりの厳密な制約が緩い
-
restart:無し、最小構成 - Cloudflare / HTTPS 無し
本番環境の特徴
-
Dockerfile.prodで最適化ビルド -
APP_ENV=production固定 - Vite の
base="/"必須 - FRONTEND_URL / API_URL / STRIPE_KEYS / SMTP / Mongo 認証 など完全版の
.envを要求 - MongoDB を外部公開しない
- Redis & Mongo の永続化
restart: unless-stopped- Cloudflare Tunnel で HTTPS 公開
- Webhook 受信のため Stripe CLI 必須
これらの仕様と .env.production の設定漏れが大半の不具合につながった。
2. 主要トラブルと解決方法
2-1. MongoDB が起動しない(Illegal instruction)
原因
mongo:6.0 は AVX 必須。自宅サーバーの CPU が非対応でクラッシュ。
ログ抜粋
Illegal instruction (core dumped)
解決
→ mongo:4.4 にダウングレードして起動。
2-2. (AuthenticationFailed) SCRAM-SHA-1 で接続不可
原因
- 初期ユーザーが存在しない状態で認証が有効化されていた
-
SCRAM-SHA-1で接続しようとして失敗
解決
- Mongo に直接入ってユーザー再作成
- URI に
authMechanism=SCRAM-SHA-256を追加
2-3. Redis の DNS 解決失敗
原因
Compose 本番に Redis サービスが存在しなかった。
ログ
lookup redis on 127.0.0.11:53: no such host
解決
redis:7-alpine を compose に追加し、backend の depends_on を修正。
2-4. Stripe 公開キーが空文字で Stripe JS が起動不能
原因
-
frontend/.env.productionに必要な環境変数が未定義- VITEは本番環境では.env.productionを読み込むとのこと。ふむ。
- 本番バンドルに空文字が焼き込まれた
症状
- 決済ボタンがクリック不能
- Stripe JS が初期化エラー
解決
-
.env.productionを正しく埋め直し npm run build --no-cache- Cloudflare & ブラウザキャッシュ削除
2-5. フロントが /subscription/ ページで白画面
原因
vite.config.ts の base: "./"
→ 本番で相対パスになり CSS/JS のパスが壊れる
エラー
Refused to execute script from … MIME type text/html
解決
base: "/" に修正して再ビルド。
2-6. OTP メール送信(SMTP)が 500 エラー
原因
Docker 本番に SMTP_* 系の環境変数が渡っていない。
解決
-
docker-compose.prod.ymlのenvironment:に SMTP を明記 - Gmail アプリパスワードを
.envに設定 - コンテナ再起動で正常化
2-7. Stripe Webhook が受信されない
原因
- Stripe CLI 側の
forward-toをlocalhost:8080にしていたが
backend は Docker 内で稼働していたため到達しない。
解決
- Ubuntu ホスト上で Stripe CLI を実行
- backend へ直接フォワード:
stripe listen –forward-to http://localhost:8080/...
2-8. Cloudflare Tunnel が永続化されない
原因
手動起動のみ → 再起動後に tunnel が落ちる。
解決
cloudflared service install
systemctl enable –now cloudflared
3. 最終的に安定稼働したポイント
- Mongo 4.4 + Redis + backend + frontend の 4 コンテナ構成
-
.envに完全な Stripe / SMTP / DB 情報 - Vite base="/" の設定
- Cloudflare Tunnel 常駐化
- Stripe Webhook のホスト直フォワード
- フロントキャッシュのパージを徹底
これで認証・OTP・Stripe 決済・サブスク・管理画面がすべて正常動作する状態に到達できた。
5. まとめ
開発と本番 compose の差分(特に環境変数・Mongo/Redis・Vite base・Stripe Keys)が、本番で発生したエラーの大半を引き起こしていた。
本番は以下 3 点を徹底することで安定した:
- 本番専用の env を正しく渡すこと
- フロントの Vite base とキャッシュを必ず整合させること
- インフラ構成(Redis/Mongo/Cloudflare)を本番前提に切り替えること
同じ構成で困っている人の参考になればなーいいなー