Next.js + FastAPI + SeleniumをVercelとRenderにデプロイしたときのエラーと解決策
ハッカソンに向けて、「会場名からライブ情報を検索するアプリ」を開発した。
フロントエンドに Next.js (Vercel)、バックエンドに FastAPI (Render) を採用し、スクレイピングに Selenium を使用した。
ローカルでは完璧に動いていたが、本番環境へのデプロイ過程でエラーが出たため、自分用として解決策をまとめる。
1. バックエンド(Render)
①:pip freeze で requirements.txt が大爆発
仮想環境で pip freeze > requirements.txt を実行したところ、関連パッケージまで全て書き出され、Renderでのビルドエラーの温床になった。(Ubuntuの設定やらなにやら)
【解決策】
クラウド環境では依存関係を自動解決してくれるため、直接インストールした主要パッケージのみを手動で記述するシンプルな形に修正した。
②:Renderの標準環境ではSelenium(Chrome)が動かない
ローカルと同じ感覚でRenderにデプロイすると、実行時に「Chromeが見つからない」というWebDriverエラーで500エラーが連発した。Renderの標準Python環境にはChrome本体がインストールされていないのが原因だった。
【解決策】
環境(Runtime)を Docker に変更し、Chromeとドライバーをインストールする Dockerfile を自作した(AIが)。
# Dockerfile
FROM python:3.10-slim
RUN apt-get update && apt-get install -y \
chromium \
chromium-driver \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "Main:app", "--host", "0.0.0.0", "--port", "10000"]
③:環境変数名の不一致による沈黙
フロントエンドと通信できたにもかかわらず500エラーが発生。Renderのログを確認すると、Python側で os.getenv("GEMINI_API_KEY") と呼び出しているのに、Renderの環境変数設定では ApiKey という名前で登録していたため、キーが見つからずクラッシュしていた。
「エラーが起きたら何よりもまずRenderのログを見る」
2. データベース(Vercel)
④:VercelでのインメモリDBリセット
ログイン機能を実装する際、最初はローカルのメモリ内(配列)にユーザー情報を保存する構成にしていた。しかし、Vercelは「サーバーレス」であるため、リクエストが完了するたびにサーバーが初期化され、登録したユーザーデータが即座に消滅してしまった。
【解決策】
Vercelが公式に提供している無料の Vercel Postgres に移行。ダッシュボードからDBを作成し、@vercel/postgres パッケージを導入して本物のデータベースへSQLで書き込むように修正した。
// 修正後:Postgresへの書き込み
import { sql } from "@vercel/postgres";
// 新規登録処理の一部
await sql`
INSERT INTO users (email, passwordHash)
VALUES (${email}, ${hashedPassword})
`;
3. フロントエンド(Next.js)
⑤:接続先が localhost のまま(通信拒否)
バックエンドをRenderにデプロイし、FastAPI側のCORS設定でフロントエンドのURLを許可した。しかし、画面からリクエストを送ると ERR_CONNECTION_REFUSED が発生。
原因は、フロントエンドの api.ts の向き先URLが http://localhost:8000 のままだったことだ。
【解決策】
向き先を Render の本番URLに変更した。
⑥:タグ削除によるGridレイアウトの崩壊
UIのブラッシュアップ中、不要な画面遷移を防ぐために タグを削除したところ、画面のレイアウトが盛大に崩壊した。
原因は、親要素の grid-cols-3 の直下に単一のブロックが存在しなくなったことで、中の要素(画像、タイトル、テキスト)がバラバラに独立したセルとして扱われてしまったためだ。
【解決策】
外した <Link> タグの代わりに <div> タグで全体を囲み直すことで、1つのブロックとして認識させ、レイアウトを修復した。
⑦:初期表示の遅延(不要なAPIフェッチ)
検索ページを開いた際、会場リストを取得するためのAPI通信を行っていたため、画面の表示にタイムラグが生じていた。
【解決策】
現段階では「マリンメッセ福岡」しかスクレイピングの対応ができていないため、useEffect での通信をまるごと削除し、初期値としてハードコーディングすることで画面表示速度を速めた(ここは今後の展望)
// 修正前:通信して待機
// const [venues, setVenues] = useState<string[]>([]);
// useEffect(() => { fetchVenues().then(setVenues) }, []);
// 修正後:ハードコーディングで即時表示
const [venues, setVenues] = useState<string[]>(["マリンメッセ福岡"]);
const [selectedVenue, setSelectedVenue] = useState<string | null>("マリンメッセ福岡");
まとめ
-
サーバーレス(Vercelなど)ではファイルの書き込みやメモリ保存はできない。DBを用意する
-
RenderでSeleniumを動かすならDocker化&ヘッドレス設定が必須
-
謎のエラーが出たら、まずはバックエンドのログを見る