Skip to content

systemd で Bot を常駐させる(学習用)

関連: 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 をサービス専用にする(他プロセスと隔離)

補足:

  • ExecStartsource .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 その登録を外す(今動いているプロセスは止めない)

startenable を同時にやる短縮形:

sudo systemctl enable --now finance-manager

学習チェック(ここまでできたら)

自分の言葉で答えられるか確認:

  1. After=Wants= の違いは?
  2. なぜ User=debian にして root で動かさない?
  3. WorkingDirectory が無いと何が困りそう?
  4. systemctl startenable の違いは?
  5. ログはどこを見る?

(詰まったら 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

よくある失敗

症状 見ること
statusactivating / すぐ死ぬ 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 は答え合わせ・再インストール用。