systemd で Bot を常駐させる(学習用)
このドキュメントは コピペ一発より、自分で unit を書いて理解する 前提。
完成形の参考は deploy/finance-manager.service(答え合わせ用)。
そもそも systemd とは
Linux で「OS 起動後に何を動かすか」「落ちたらどうするか」を管理する仕組み。
| 用語 | 意味 |
|---|---|
| unit | systemd が扱う設定の1単位。今回は .service |
| service | 長く動くプロセス(Bot・DB・Web サーバなど) |
| systemctl | 起動・停止・有効化を操作するコマンド |
| journald / journalctl | サービスの標準出力・標準エラーを集めるログ |
いままで:
SSH ログイン → ./scripts/run.sh → SSH 切断 → プロセスも死ぬ
目指す姿:
OS 起動 → systemd が Bot を起動 → SSH なしでも動き続ける
落ちたら自動で再起動
前提チェック
VM 上で確認:
whoami
# → debian であること(違うなら後で User= を合わせる)
pwd
ls ~/finance-manager/scripts/run.sh
ls ~/finance-manager/.venv
ls ~/finance-manager/.env
二重起動しない
いま別ターミナルで ./scripts/run.sh しているなら Ctrl+C で止める。
同じ Bot を二重起動すると Discord 側で変なことが起きやすい。
手動起動がまだ動くかも一度確認しておくと安心:
cd ~/finance-manager
./scripts/run.sh
# Logged in as ... を見たら Ctrl+C
手順 1: unit ファイルを自分で作る
システム全体のサービス定義はここに置く慣習:
/etc/systemd/system/名前.service
編集には root が必要なので sudo を使う。
sudo nano /etc/systemd/system/finance-manager.service
(vim でも可。)
下の内容を セクションごとに理解しながら 手入力する。
[Unit] … 「このサービスは何か・いつ起動するか」
[Unit]
Description=finance-manager Discord bot
Documentation=https://github.com/nakajima923/finance-manager
After=network-online.target
Wants=network-online.target
| 行 | 意味 |
|---|---|
[Unit] |
共通メタ情報のセクション開始 |
Description= |
systemctl status に出る人間向け説明 |
Documentation= |
ドキュメント URL(任意だが学習・運用で便利) |
After=network-online.target |
ネットワークが上がってから 起動を始める(順序) |
Wants=network-online.target |
可能ならネットワーク待ちを一緒に引っ張る(必須依存より弱い) |
補足:
After=は「順序」だけで、「相手が成功したこと」は保証しない- Discord Bot は外向き接続が要るので、ネットワーク後起動が無難
[Service] … 「何をどう実行するか」
[Service]
Type=simple
User=debian
Group=debian
WorkingDirectory=/home/debian/finance-manager
ExecStart=/home/debian/finance-manager/scripts/run.sh
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1
NoNewPrivileges=true
PrivateTmp=true
| 行 | 意味 |
|---|---|
[Service] |
実行方法のセクション |
Type=simple |
ExecStart のプロセス自体が本体。すぐ終わるワンショットではない |
User= / Group= |
root ではなく一般ユーザーで動かす(事故時の被害を限定) |
WorkingDirectory= |
カレントディレクトリ。.env や相対パスの基準になる |
ExecStart= |
実際に起動するコマンド(絶対パス推奨) |
Restart=always |
落ちても(ほぼ)いつも再起動 |
RestartSec=5 |
再起動までの待ち秒。連打で API を叩かないため |
Environment=PYTHONUNBUFFERED=1 |
Python の出力をバッファせず、journal にすぐ出やすくする |
NoNewPrivileges=true |
権限昇格しにくくする(基本の硬化) |
PrivateTmp=true |
/tmp をサービス専用にする(他プロセスと隔離) |
補足:
ExecStartにsource .venv/bin/activate && python ...と書かなくてよい。
scripts/run.shが venv とPYTHONPATHを面倒見ているRestart=on-failureにすると「正常終了(0)」では再起動しない。
Bot は意図せず終了しがちなので、まずはalwaysが扱いやすい
[Install] … 「enable したときどこにぶら下げるか」
[Install]
WantedBy=multi-user.target
| 行 | 意味 |
|---|---|
[Install] |
systemctl enable 用の情報 |
WantedBy=multi-user.target |
通常のマルチユーザー起動(サーバの普通の起動段階)に入れる |
enable すると、だいたい次のようなシンボリックリンクが作られる:
/etc/systemd/system/multi-user.target.wants/finance-manager.service
→ /etc/systemd/system/finance-manager.service
保存して nano を抜ける(Ctrl+O → Enter → Ctrl+X)。
手順 2: systemd に読み込ませる
ファイルを置いただけでは、systemd はまだ知らない。
sudo systemctl daemon-reload
| コマンド | 意味 |
|---|---|
daemon-reload |
unit ファイルの追加・変更を再読み込み |
手順 3: 今すぐ起動してみる(まだ enable しない)
まず一回だけ動かして、設定ミスを潰す。
sudo systemctl start finance-manager
sudo systemctl status finance-manager
| コマンド | 意味 |
|---|---|
start |
今この瞬間だけ起動(再起動後は自動では上がらない) |
status |
動いているか・最近のログ数行 |
active (running) ならよい兆候。
ログを追う:
journalctl -u finance-manager -f
| オプション | 意味 |
|---|---|
-u finance-manager |
この unit のログだけ |
-f |
follow(更新を追い続ける)。止めるのは Ctrl+C |
Logged in as ... が見えたら成功。Discord に一言送って応答も確認。
手順 4: 开机時に自動起動させる
sudo systemctl enable finance-manager
| コマンド | 意味 |
|---|---|
enable |
ブート時に自動で start されるよう登録 |
disable |
その登録を外す(今動いているプロセスは止めない) |
start と enable を同時にやる短縮形:
sudo systemctl enable --now finance-manager
学習チェック(ここまでできたら)
自分の言葉で答えられるか確認:
After=とWants=の違いは?- なぜ
User=debianにしてrootで動かさない? WorkingDirectoryが無いと何が困りそう?systemctl startとenableの違いは?- ログはどこを見る?
(詰まったら deploy/finance-manager.service と見比べる。)
日常運用チートシート
| やりたいこと | コマンド |
|---|---|
| 状態 | sudo systemctl status finance-manager |
| 止める | sudo systemctl stop finance-manager |
| 起動 | sudo systemctl start finance-manager |
| 再起動 | sudo systemctl restart finance-manager |
| コード更新後 | cd ~/finance-manager && git pull && sudo systemctl restart finance-manager |
| 直近100行 | journalctl -u finance-manager -n 100 --no-pager |
| 追いかけ | journalctl -u finance-manager -f |
pip で依存を足したあと:
cd ~/finance-manager
source .venv/bin/activate
pip install -r requirements.txt
sudo systemctl restart finance-manager
よくある失敗
| 症状 | 見ること |
|---|---|
status が activating / すぐ死ぬ |
journalctl -u finance-manager -n 50 --no-pager |
.env が読めない |
WorkingDirectory とファイル権限(debian が読めるか) |
Permission denied on run.sh |
chmod +x ~/finance-manager/scripts/run.sh |
| Discord に二重反応 | 手動 run.sh がまだ生きていないか ps aux \| grep finance |
| unit を直したのに変わらない | sudo systemctl daemon-reload を忘れていないか |
リポジトリの参考ファイル
手入力が正。リポジトリの deploy/finance-manager.service は答え合わせ・再インストール用。