【Railway】GitHub Actions で定期的にサーバーをリスタートさせる
2026.08.30

どもです。
前回「ひたすら安く個人開発サービスを運用する計画」とのことで記事を書かせていただきましたが、しばらく動かしていると「そういえば定期的に再起動かけておきたいなぁ」という気持ちになってきまして。
長時間動かしっぱなしにしていると、まぁ色々と溜まってくるものがあるわけです。だったら決まった時間に一回サッと再起動しておけば良いのでは、と。
ということで、今回はその「Railway のサービスを定期的にリスタートさせる」仕組みを GitHub Actions で組んだので、その内容をまとめた形になります。
やりたかったこと
- Railway 上で動かしているサービスを、毎日決まった時間に自動でリスタートさせたい
- Railway 側だけで完結する定期実行の仕組みは用意しなかったので、外から叩く形にする
- せっかくなので手動でもポチッと実行できるようにしておきたい
そこで白羽の矢が立ったのが GitHub Actions です。cron でスケジュール実行できますし、リポジトリさえあればすぐ動かせるので、この手の「たまに叩くだけ」の用途にはピッタリなんですよね。
方針は「GitHub Actions から Railway CLI を叩く」
やることはシンプルで、Actions のランナー上に Railway CLI を入れて、railway restart を実行するだけ。
npm install -g @railway/cli
あとは対象のプロジェクト・環境・サービスを指定してリスタートを投げれば良い、という話……のはずだったのですが、ここで一つハマりポイントがありました。
ハマったところ:成功しても CLI が終了しない
これがなかなか厄介でして。
railway restart を実行すると、リスタート自体はちゃんと成功するんです。成功するんですが、その後 CLI が接続を掴んだまま exit してくれないことがある。
Actions 側からすると「まだ処理が終わっていない」ようにしか見えないので、ジョブがずーっと回りっぱなしになるわけです。いかぁーん。GitHub Actions は実行時間が課金対象なので、これを放置するとジワジワとコストが溶けていきます。
なので、次の二段構えで対処しました。
timeout 60で CLI を強制的に打ち切る- 打ち切られたときの終了コード
124は「成功扱い」にする
timeout コマンドは、対象のコマンドを時間切れで終わらせたときに終了コード 124 を返します。今回は「リスタート自体はもう成功している」前提なので、|| [ $? -eq 124 ] と書いておくことで、タイムアウトで落ちてもジョブ全体は成功として扱われるようにしています。
ちょっと強引に見えるかもしれませんが、restart は投げた時点で仕事が終わっているので、これで十分かと思います。
さらに保険として、ジョブ全体にも timeout-minutes を設定しておきます。ハングしたときに Action の実行時間(=コスト)が暴走しないようにする安全弁ですね。ここは付けておけば安心感がまるで違います。
実際のワークフロー
というわけで、最終的に出来上がったのがこちらになります。.github/workflows/ 配下に置いてあげてください。
name: Daily Railway Restart
on:
schedule:
# 毎日日本時間の午前5時(UTC 20:00)に実行する場合
- cron: '0 20 * * *'
workflow_dispatch: # 手動実行も可能にする場合
jobs:
restart:
runs-on: ubuntu-latest
timeout-minutes: 5 # ハング時の Action 分(コスト)暴走を防ぐ安全弁
steps:
- name: Install Railway CLI
run: npm install -g @railway/cli
- name: Restart Railway Service
timeout-minutes: 2
# restart 成功後も CLI が接続を掴んで exit しないことがあるため、
# timeout で強制終了しつつ「タイムアウト時は成功扱い」にする
run: |
timeout 60 railway restart --yes \
--project <your-project-id> \
--environment <your-environment> \
--service <your-service-name> \
|| [ $? -eq 124 ]
env:
RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
<your-project-id> などの箇所は、ご自身の環境の値に置き換えてください。詳しくは後述します。
各パートの補足
実行スケジュール
on:
schedule:
- cron: '0 20 * * *'
workflow_dispatch:
GitHub Actions の cron は UTC 基準なので、日本時間で考えるときは 9 時間ズラして書く必要があります。ここ、地味に間違えやすいところなんですよね。
今回は日本時間の午前5時に走らせたかったので、UTC では前日の 20:00、つまり 0 20 * * * という指定になります。
workflow_dispatch を並べて書いておくと、GitHub の Actions 画面から手動でも実行できるようになります。動作確認のときに毎回 cron の時間を待つのはさすがに厳しいので、これは入れておいたほうが楽になります。
タイムアウト周り
timeout-minutes: 5
ジョブ全体の上限。前述の通り、これが暴走防止の安全弁になります。
timeout-minutes: 2
こちらはステップ単位の上限。timeout 60 で CLI を切っているので通常はそこで終わりますが、念のためもう一枚重ねている形です。
リスタートの指定
timeout 60 railway restart --yes \ --project <your-project-id> \ --environment <your-environment> \ --service <your-service-name> \ || [ $? -eq 124 ]
--yes… 確認プロンプトをスキップします。CI では対話できないので必須です--project… 対象プロジェクトの ID。Railway のプロジェクト URL に含まれる UUID がそれです--environment… 環境名。productionやstagingなど、ご自身で設定している環境名を指定します--service… 対象のサービス名。Railway のダッシュボードに表示されている名前です
CI 環境では対話的な選択ができないので、プロジェクト・環境・サービスを全部明示してあげるのがポイントになります。
ちなみにプロジェクト ID をソースに直書きしたくない場合は、こちらも Secrets に逃がして --project ${{ secrets.RAILWAY_PROJECT_ID }} のように書いてあげると良いかと思います。
トークンの受け渡し
env:
RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
Railway CLI の認証は環境変数 RAILWAY_API_TOKEN 経由で行います。トークンはリポジトリの Secrets(Settings → Secrets and variables → Actions)に RAILWAY_API_TOKEN という名前で登録しておいてください。
間違ってもワークフローに直書きしないように。ここだけは気をつけましょう。
まとめ
- Railway の定期リスタートは GitHub Actions の
scheduleで組める railway restartは成功しても CLI が exit しないことがあるtimeout 60+|| [ $? -eq 124 ]で「タイムアウトは成功扱い」にして回避- ジョブにもステップにも
timeout-minutesを入れて、コスト暴走の安全弁にしておく
「成功しているのにジョブが終わらない」というのは、原因が分かるまでが一番モヤモヤするやつでして。分かってしまえば timeout 一発で済む話なんですが、ここに辿り着くまでが長かった。。
まぁ何にせよ、これで毎朝5時に勝手にリフレッシュしてくれる環境が手に入りました。人間より早起きなのが少し悔しいですがw
ではではぁ。またまたぁ。










