Supabase 無料プランの自動一時停止で本番が落ちた話 — GitHub Actions keepalive 対策
JurisCode.AI の個人開発プロダクト Lifefolio で、ある朝突然ログインも同期もできなくなりました。原因は Supabase 無料プランの仕様——7日間アクセスがないとプロジェクトが自動一時停止される——です。この記事では、実際に起きた症状、数分で終わる復旧手順、そして GitHub Actions の cron で定期 ping を打つ keepalive の恒久対策(workflow 全文つき)をまとめます。


何が起きたか
Lifefolio は無料ベータとして公開しており、バックエンドに Supabase の Free プランを使っています。ある日ふと本番を開くと、ログインが失敗し、既存ユーザーのデータ同期も全滅していました。
ブラウザのコンソールを見ると、Supabase のホスト名の解決自体が失敗しています。ERR_NAME_NOT_RESOLVED、つまり NXDOMAIN です。サーバーがエラーを返しているのではなく、接続先そのものが消えている状態でした。アプリ側のコードは1行も変えていないのに、です。
この「エラーが返ってこない」という点が、原因の切り分けをいちばん遅らせました。500 や 401 ならアプリ側かキー周りを疑えますが、名前解決の失敗はもっと手前の層の話です。デプロイもしていない、環境変数も触っていない——それなのにホストが消えている、という状況はコードの中を探しても答えが出ません。
なぜ起きるか: Free プランの仕様

Supabase の Free プランには「プロジェクトへのアクティビティが7日間ないと、プロジェクトを自動的に一時停止(pause)する」という仕様があります。一時停止されるとデータベースだけでなく API のエンドポイントごと止まるため、外から見るとホストが存在しない(NXDOMAIN)ように見えます。
Lifefolio はベータ公開直後でアクセスがまばらだったうえ、開発の主戦場が別プロダクトに移っていた時期でした。ダッシュボードすら1週間開かなければ、条件は簡単に満たされます。個人開発の「作った直後の静かな時期」こそ、いちばん踏みやすい罠だと思います。
言い換えると、この仕様が効くのは「サービスが伸び悩んでいる時期」ではなく「開発者が別のことをしている時期」です。ユーザーが来ていればアクセスは発生しますが、公開直後のプロダクトはそもそもアクセスが薄い。そして作った本人も、次のプロダクトや別の締切に向かっていて見ていない。人の注意が離れた瞬間に条件が満たされるので、気づく人がいない状態で止まります。
もうひとつ厄介なのは、止まったことが自分のアプリのログに残らない点です。落ちているのはバックエンド側で、フロントは単に「つながらない」だけ。ユーザーが黙って離脱していれば、問い合わせも来ません。
復旧手順: 数分で戻る
復旧自体は簡単です。方法は2つあります。
- ダッシュボードから: 対象プロジェクトを開くと「Restore」ボタンが出ているので押すだけ。数分で復帰します
- Management API から: アクセストークンがあれば curl 一発で復旧をキックできます
curl -X POST "https://api.supabase.com/v1/projects/<project-ref>/restore" \
-H "Authorization: Bearer <management-api-access-token>"Lifefolio もダッシュボードの Restore から数分で全機能が復旧しました。データは消えていません。ただし「気づくまでの間ずっと落ちている」のが本当の被害です。
手順として書き起こすと、やることは4つだけです。(1) Supabase のダッシュボードで対象プロジェクトを開く (2)「Restore」ボタンを押す (3) 数分待って復帰を確認する (4) 本番でログインとデータ同期を1往復ためす。Management API を使う場合は、(2) が上の curl 1発に置き換わります。project-ref はダッシュボードの URL に含まれているプロジェクトの識別子、アクセストークンは Management API 用に発行するものです。
ここで押さえておきたいのは、復旧の所要時間が「数分」である一方、検知の所要時間は何日にもなりうるということです。直す作業は一瞬なので、改善すべきなのは手順ではなく「止まらないようにする」側と「止まったら分かる」側だけです。
恒久対策: GitHub Actions で keepalive

「7日間アクセスなし」が条件なら、7日未満の間隔で機械的にアクセスすればいい。GitHub Actions の cron で3日ごとに Supabase の REST API を ping する workflow を組みました。全文はこれだけです。
name: Supabase keepalive
on:
schedule:
- cron: "17 20 */3 * *"
workflow_dispatch:
jobs:
ping:
runs-on: ubuntu-latest
steps:
- name: Ping Supabase REST API
run: |
curl --fail -sS -o /dev/null \
"${{ secrets.SUPABASE_URL }}/rest/v1/<table>?select=id&limit=1" \
-H "apikey: ${{ secrets.SUPABASE_ANON_KEY }}" \
-H "Authorization: Bearer ${{ secrets.SUPABASE_ANON_KEY }}"ポイントは3つあります。
- キーは anon(publishable)キーで十分。テーブルは RLS で保護されているので、読める行がなくてもリクエスト自体がアクティビティとして数えられます。service_role キーを CI に置く必要はありません
- secrets に `SUPABASE_URL` と `SUPABASE_ANON_KEY` を登録し、workflow には値を直書きしない
- cron の分は0分ちょうどを避ける。毎時0分は GitHub Actions 全体で混雑し、遅延やスキップが起きやすいため、
17 20 */3 * *のように分をずらしておくと安定します
不安なら */3(3日ごと)を毎日にしても、無料枠のコストは誤差です。さらに Management API のアクセストークンを secrets に足せば、「ping が失敗したら restore を叩く」ところまで自動化できます。
ping の宛先を REST API にしたのには理由があります。ダッシュボードを開くのは人間の習慣に依存しますが、REST API へのリクエストは機械が確実に繰り返せます。しかも読むのは select=id&limit=1 の1行だけなので、テーブルの中身が増えても負荷は変わりません。RLS で保護されたテーブルなら、anon キーで読める行が0件でも構いません。必要なのはデータではなく「アクセスがあった」という事実です。
<table> の部分には、実際に存在するテーブル名を入れます。存在しないテーブル名を書くとリクエストはエラーになり、curl --fail を付けているので workflow も失敗します。これは一見まずいようですが、設定ミスがその場で赤くなるという意味では都合がよい挙動です。
keepalive が動いているかの確かめ方
仕込んだだけで安心しないために、入れた直後に1回は手で回しておきます。workflow に workflow_dispatch を書いてあるのは、そのための入口です。Actions のタブから手動で実行して緑になれば、URL・キー・テーブル名の3点が揃っていることが確認できます。
curl --fail -sS -o /dev/null の組み合わせも、確認のしやすさを意識した指定です。--fail は HTTP のエラー応答を終了コードに反映させるので、画面上は200でないと緑になりません。-sS は余計な進捗表示を消しつつエラーだけは出し、-o /dev/null でレスポンス本文をログに残しません。つまりログには結果だけが残り、キーやデータは残らないという形になります。
注意点は、cron の実行が GitHub Actions 側の都合で遅れたりスキップされたりすることです。だからこそ間隔は7日ギリギリではなく3日に取っています。余裕を2回ぶん持たせておけば、1回飛んでも条件には届きません。逆に「6日ごと」のような詰めた設定は、遅延が1回起きただけで意味を失います。
まとめ: チェックリスト
Supabase 無料プランで本番を運用しているなら、次を確認しておくことをおすすめします。
- Free プランは7日間アクセスなしで自動一時停止することを知っておく(症状は NXDOMAIN)
- 落ちたらダッシュボードの Restore か Management API の
POST /v1/projects/{ref}/restoreで数分で復旧できる - GitHub Actions の cron で7日未満の間隔の keepalive ping を仕込む(anon キー + RLS で安全に)
- cron の分は
17などにずらして、0分の混雑を避ける
Lifefolio の開発では、こうした障害も含めて品質ゲートの運用に学びを還元しています。その開発体制自体の話は「Claude Code と多エージェントで6日間でプロダクトを作った開発体制の話」に書いたので、あわせてどうぞ。
コメント
#Supabase#GitHub Actions#個人開発