アプリを常駐させる方法|systemdとcron @rebootの比較
自作のWebアプリをサーバーで動かし続ける方法として、起動スクリプトとcronの@rebootで起動する方法と、systemdのサービスにする方法を比べます。落ちたときの再起動・ログ・再起動の後の失敗の起きやすさから選ぶ基準を解説します。
目次
この記事でわかること
- 自作のWebアプリを動かし続ける2つの方法(cronの@rebootとsystemd)の違い
- 起動スクリプトとPIDファイルで起動を判定するときの落とし穴
- systemdのサービスの最小の形と、状態とログの見方
- どちらを選ぶかの基準と、Claude Codeへの頼み方
結論から書くと、落ちたときに自動で起動し直したい、ログをまとめて読みたいならsystemd、root権限を使えない・今の運用を大きく変えたくないなら起動スクリプトと@rebootです。@rebootを使う場合は、再起動の後に本当に起動したかを確かめる手順を決めておきます。
2つの方法の違い
| 点 | @reboot | systemd |
|---|---|---|
| 起動 | 再起動後に1回 | 起動時と条件 |
| 落ちたら | そのまま | 起動し直せる |
| プロセス | PIDファイル | systemdが管理 |
| ログ | 自分でファイルへ | journalctl |
| 権限 | 一般ユーザー | 置き場所はroot |
Gunicornの公式の文書も、systemdやsupervisordのようなプロセスを見張る仕組みで動かすことを勧めています。その場合、Gunicornのデーモンのモードは使わないとされています。
このサイトの運用: 起動スクリプトと@reboot
このサイトのアプリは、systemdを使わずに動かしています。起動スクリプトがGunicornをnohupで起動し、その番号をPIDファイルに書き、crontabの@rebootで再起動の後に呼び出す形です。2026年10月17日に確かめたとき、同じサーバーのcrontabには、このような@rebootの行が5本ありました。
【用途】@rebootで起動しているものを一覧にする /【実行場所】サーバー(アプリを動かしているユーザー) /【状態変更】なし(中身を見るだけ)
crontab -l | grep '@reboot'
crontab(5)の説明では、@rebootは再起動の後に1回だけ動きます。また、cronから動くコマンドのシェルは/bin/shで、ログインしたときと同じ環境とは限りません。起動スクリプトの中では、作業フォルダへの移動と、venvの中のコマンドを絶対パスで書いておくと安心です。
Gunicornの動かし方そのものはFastAPIをGunicornとUvicornで動かす方法で、サーバー全体の作り方はClaude CodeでAlmaLinuxサーバーを構築・運用する方法で紹介しています。
PIDファイルで起動を判定する落とし穴
起動スクリプトでよく使うのが、「PIDファイルがあり、その番号のプロセスが生きていれば、もう起動しているとみなす」判定です。このサイトの起動スクリプトも、この判定を使っています。
この判定には弱点があります。サーバーを再起動するとプロセスの番号は振り直されるため、前回のPIDファイルに残った番号を、再起動の後に別のプロセスが使っていることがあります。すると、アプリは止まっているのに「起動中」と判断して、起動を飛ばします。
2026年10月12日にサーバーを再起動したとき、このサイトのアプリは起動しましたが、同じサーバーの別のアプリはこの判定に当たって起動せず、外からは503になりました。このサイトの起動スクリプトも同じ判定なので、たまたま当たらなかっただけです。原因の切り分けはサーバー障害の切り分けをClaude Codeと進める方法にまとめています。
@rebootを使い続けるなら、次のどちらかで弱点を小さくします。
- 再起動の後に、アプリの応答を外から確かめる手順を必ず入れる
- 判定で、番号のプロセスが本当に目的のアプリかどうかまで確かめる
systemdのサービスの最小の形
systemdのサービスにすると、起動したプロセスをsystemdが覚えているため、PIDファイルが要りません。systemd.serviceの説明でも、新しく作るものではPIDファイルを避けるよう書かれています。
次は、最小の形の例です。管理者が作るサービスのファイルは/etc/systemd/systemに置きます。
【用途】サービスのファイルの例を読む /【実行場所】/etc/systemd/system/myapp.service(root権限が要る場所) /【状態変更】なし(例を示すだけ。この記事の検証では作成・起動していません)
[Unit]
Description=myapp (Gunicorn)
After=network.target
[Service]
User=your-user
WorkingDirectory=/home/your-user/apps/myapp
ExecStart=/home/your-user/apps/myapp/venv/bin/gunicorn -k uvicorn.workers.UvicornWorker -w 2 -b 127.0.0.1:8081 app.main:app
Restart=on-failure
[Install]
WantedBy=multi-user.target
Restart=の既定は「起動し直さない」です。on-failureにすると、プロセスが0以外の終了コードで終わったときなどに起動し直します。起動し直すまでの待ち時間(RestartSec=)の既定は100ミリ秒です。Gunicornの公式の例は、準備ができたことを知らせる形(Type=notify)とソケットを組み合わせたもので、ここではより簡単な形にしています。
置いたファイルを読み込ませ、起動時に動くように登録するには、root権限で次を実行します。enableは、[Install]の内容に従って登録するだけで、すぐには起動しません。
【用途】サービスを読み込ませ、登録して起動する /【実行場所】サーバー(sudoの使える人) /【状態変更】あり(サービスの登録と起動。先に今の起動の方法を止める手順を決めてから)
sudo systemctl daemon-reload
sudo systemctl enable myapp.service
sudo systemctl start myapp.service
@rebootから切り替えるときは、先に今のcrontabの内容をファイルに書き出してバックアップを取ります。そのうえで、同じアプリを2つの方法で同時に起動しないよう、crontabの行を外す手順と、戻すときの手順を決めておきます。
状態とログの見方
systemdのサービスにした後は、状態とログを次のように確かめます。journalctlの-uはサービスを、-bは今回の起動の後のログだけを選びます。
【用途】サービスの状態と、今回の起動の後のログを見る /【実行場所】サーバー /【状態変更】なし(中身を見るだけ)
systemctl status myapp.service
journalctl -u myapp.service -b
statusで「active (running)」と出て、ログに起動の行があれば動いています。ログを一般のユーザーで読めるかは、サーバーの設定によります。
Claude Codeに比較と案を頼む
今の起動の方法を調べさせ、systemdにする場合の案を出させるところまでは、Claude Codeに頼めます。置く作業はroot権限が要るので、案を読んでから自分で決めます。
【用途】今の起動の方法を調べさせ、サービスのファイルの案を出させる /【実行場所】Claude Codeに頼む文 /【状態変更】なし(案を受け取るだけ)
myapp を常駐させる方法を見直したいです。
- まず、crontab の @reboot の行と起動スクリプトを読み、今どう起動しているかを説明してください
- 次に、systemd のサービスにする場合のファイルの案と、@reboot から切り替える手順・戻す手順を書いてください
- ファイルを置く・crontab を変える・サービスを登録するなどの変更は行わないでください
案を示したら、私が読んで決めるまで待ってください。
つまずきやすいところ
- @rebootの起動スクリプトが、手で実行したときと違う動きをする: cronのシェルは/bin/shで、ログインしたときの環境とは限りません。パスは絶対パスで書きます
- PIDファイルが残ったまま再起動する: 前回の番号を別のプロセスが使っていると、起動を飛ばすことがあります
- systemdに切り替えた後もcrontabの行が残っている: 同じアプリを2回起動しようとして、ポートの取り合いになります
- Gunicornのデーモンのモードをsystemdと一緒に使う: Gunicornの公式の文書では、見張る仕組みと一緒に使うときは使わないとされています
どちらを選ぶかの判断のポイント
- root権限を使えるか: 使えない、または共用のサーバーで管理する人が別にいるなら、まず起動スクリプトと@rebootで、確認の手順を整えます
- 落ちたときにどれだけ困るか: 夜中に止まると困るアプリなら、Restart=で起動し直せるsystemdが向いています
- ログをどこで読みたいか: アプリごとのファイルで足りるなら今のままでも構いません。サーバーのほかのログと一緒に読みたいならsystemdです
このサイトは、今は起動スクリプトと@rebootのままです。起動の判定を直すか、systemdに移すかは、今後の候補として記録しています。
まとめ
- @rebootは再起動の後に1回動くだけで、途中で止まったアプリを起動し直しません
- PIDファイルの判定は、再起動の後に起動を飛ばすことがあります
- systemdのサービスは、Restart=・journalctl・プロセスの管理の面で有利ですが、置き場所はroot権限が要ります
- どちらを選んでも、再起動の後にアプリが応答するかを確かめる手順を決めておきます
よくある質問
cronの@rebootだけで、アプリを常駐させてもよいですか?
動かすことはできます。このサイトも起動スクリプトを@rebootで呼び出しています。ただし、@rebootは再起動の後に1回動くだけで、途中でアプリが止まったときに起動し直す仕組みはありません。
systemdのサービスにすると、何がよくなりますか?
Restart=を設定すると、アプリが異常に終了したときに起動し直せます。ログはjournalctlでサービスごとに読め、起動したプロセスをsystemdが覚えているため、PIDファイルを自分で管理する必要がなくなります。
systemdのサービスを作るには、何が必要ですか?
管理者が作るサービスのファイルは/etc/systemd/systemに置きます。この場所は通常rootでないと書けないため、sudoの使える人の作業になります。共用のサーバーでは、管理する人と相談してから決めます。
再起動の後にアプリだけ起動しないのはなぜですか?
起動スクリプトが、前回のPIDファイルの番号のプロセスがあれば起動しない作りだと、再起動の後に同じ番号を別のプロセスが使っていたときに起動を飛ばします。このサイトと同じサーバーの別のアプリで、実際に起きました。
Claude Codeにsystemdのサービスを作らせてもよいですか?
サービスのファイルの案を書かせて、内容を確かめるところまでなら頼めます。置く・有効にする作業はroot権限が要るため、案を読んでから自分で実行します。