systemd でサービスを常駐させる
自作のスクリプトを systemd に登録し、Proxmox から本当に電源を落として入れ直したあとに、サービスが自力で起き上がることを確かめます。「自動起動が設定できている」と「実際に起き上がる」は別物です。
| 所要時間 | 約 40 分 |
|---|---|
| 章タイプ | standard |
| 前提知識 | Part 1 Chapter 6(シェルスクリプトを書いて実行できる) |
| 使用機材 | 踏み台 workstation01 + 演習用サーバ learner01(Proxmox 電源操作あり) |
| 関連章 | 後: Chapter 2「journalctl でログを運用者として読む」/ 後: Chapter 5「ディスクを拡張する」 |
電源を落として入れ直しても、サービスは自分で起き上がるか
サーバを運用していると、いつか必ずこの場面に出会います。
深夜 2 時。停電アラートが鳴った。UPS が切れて、サーバの電源が落ちた。 朝、電源を入れ直した ── Web サービスは自動で起き上がっているか?
手で python3 app.py & や ./server.sh を叩いて動かしているだけなら、答えは「起き上がらない」です。誰かが SSH でログインしてコマンドを打つまで、サービスは止まったままになります。
Linux の標準的な解が systemd です。サービスを systemd に「登録」しておけば、電源断や再起動のあとでも OS の起動手順の一部としてサービスが立ち上がります。設定ファイル(ユニットファイル)に WantedBy=multi-user.target と書くだけで、その仲間入りができます。
この章の核心は 本当に電源を切ってみることです。
① サービスを systemd に登録する(ユニットファイルを書く)
↓
② systemctl enable で「OS 起動時に自動起動する」設定を入れる
↓
③ Proxmox ホストから電源断相当(qm stop)→ 再投入(qm start)
↓
④ SSH で戻り、systemctl is-active が active ── enable が効いている証拠
クラウドの「インスタンスを再起動」ボタンの裏側では、OS が起動するたびにこの仕組みが動いています。ただし、そこで何が起きているかは画面からは見えません。本章では自分でユニットファイルを書き、本物の電源断で確かめます。
hello-logger を systemd に登録し、Proxmox から電源を落として入れ直したあとに自動起動していることを確認します。章末のクリーンアップで演習前のクリーン状態に戻します。この章を終えるとできること
サービス常駐の 4 動詞を手に覚えます。
3 つの動詞で見る
ユニットにする
次回自動起動
越えられるか
systemd のしくみを解きほぐす
1. ユニットファイルの構造:3 つのセクション
systemd は Linux の「最初のプロセス(PID 1)」として起動し、そのあとのすべてのサービス・マウント・タイマーを管理します。管理の単位を ユニット(unit) と呼び、その設定ファイルを ユニットファイル と言います。
サービス用のユニットファイル(.service)は 3 つのセクションでできています。
[Unit] ── このユニット自身の説明と、起動順序の依存関係 Description=Hello Logger - 演習用タイムスタンプ記録サービス After=network.target [Service] ── プロセスをどう起動・管理するか Type=simple ExecStart=/usr/local/bin/hello-logger.sh Restart=on-failure RestartSec=5s StandardOutput=journal StandardError=journal [Install] ── どの起動フェーズに組み込むか WantedBy=multi-user.target
| セクション | 主なキー | 役割 |
|---|---|---|
[Unit] | After= | 依存するサービスより後に起動する、という順序の指定 |
[Service] | ExecStart= | 起動するコマンド(絶対パスで書く) |
[Service] | Restart= | 異常終了したときに自動で再起動するか |
[Install] | WantedBy= | どの「起動ターゲット」に組み込むか |
/etc/systemd/system/ に置いたユニットファイルは、systemctl daemon-reload を実行して初めて systemd に読み込まれます。ファイルを書いただけでは反映されません。
2. enable と start の違い:自動起動と即時起動
ここが最も混乱しやすいところです。名前が似ていますが、まったく別のことをします。
systemctl start <svc> # 今すぐ起動する。再起動したら消える systemctl enable <svc> # 次回起動時から自動起動する。今は起動しない systemctl enable --now <svc> # 両方まとめて(実務で最もよく使う)
| コマンド | 今すぐ起動する | 再起動後も起動する |
|---|---|---|
start のみ | ✅ | ❌ |
enable のみ | ❌ | ✅ |
enable --now | ✅ | ✅ |
enable が効いているかは systemctl is-enabled <svc> で確かめます。enabled なら設定済み、disabled なら毎回手で start する必要があります。
3. Restart= と enable:似て非なる 2 つの復活
どちらも「勝手に起き上がる」仕組みですが、効く場面が違います。
Restart=on-failure
└── サービスが異常終了したとき、systemd が同じ OS セッションの中で
自動的に再起動する(電源断・再起動とは無関係)
WantedBy=multi-user.target(= enable の効果)
└── OS が multi-user.target フェーズに達したとき、このサービスを起動する
(電源断後・再起動後に「OS が起動するたびに」立ち上がる根拠)
電源を切って入れ直したあとにサービスが起き上がるのは、Restart= ではなく enable(=WantedBy=)の効果です。電源が落ちれば systemd 自身も一度死ぬので、Restart= が面倒を見る相手はもういません。
実機価値:
enableが本当に効いているかは、実際に電源を切って入れ直すまで分かりません。is-enabledがenabledと答えても、それは「設定が入っている」という申告にすぎません。本章では Proxmox のqm stop/qm startで電源断相当の操作を行い、サービスが自力で起き上がる瞬間を SSH で確認します。
試してみよう:サービスを作り、電源断を越えさせる
5 秒おきに時刻を出すだけの小さなサービス hello-logger を作り、systemd に登録し、電源断のあとに自動起動することを確認します。
| 項目 | 値 |
|---|---|
| 出発地点 | 踏み台 workstation01 |
| 演習対象 | learner01(サービス作成・systemd 操作) |
| Proxmox 操作 | Proxmox ホスト(<Proxmox管理IP>) |
| ゲスト操作ユーザー | ops(NOPASSWD sudo) |
| 所要時間 | 約 30 分(8 ステップ) |
/usr/local/bin/hello-logger.sh と /etc/systemd/system/hello-logger.service の 2 ファイルだけです。STEP ⑧ のクリーンアップを上から順に実行すれば、どの段階からでもクリーン状態に戻せます。VMID の確認方法: Proxmox ホストで qm list | grep learner01 を実行すると、左端の数字が VMID です。以降 <VMID> と記します。STEP 01 · 現在の状態を確認する
workstation01 から learner01 に SSH 接続し、いま systemd で動いているサービスを眺めます。
# workstation01 から learner01 へ接続 ssh ops@learner01 # 今まさに動いているサービスの一覧 systemctl list-units --type=service --state=running
UNIT LOAD ACTIVE SUB DESCRIPTION cron.service loaded active running Regular background program processing daemon dbus.service loaded active running D-Bus System Message Bus qemu-guest-agent.service loaded active running QEMU Guest Agent rsyslog.service loaded active running System Logging Service ssh.service loaded active running OpenBSD Secure Shell server systemd-journald.service loaded active running Journal Service (中略)
いま自分が使っている SSH も ssh.service という 1 つのサービスとして systemd に管理されています。この章の終わりには、ここに hello-logger.service が並びます。
前セッションの残骸チェック:
systemctl status hello-loggerを実行してみてください。Unit hello-logger.service could not be found.と出ればクリーン状態です。activeやfailedが出る場合は前回の演習が途中で終わった名残なので、先に STEP ⑧「章末クリーンアップ」を実行してから STEP ① に戻ってください。
STEP 02 · サービスにするスクリプトを作る
5 秒おきに時刻を出力するだけのスクリプトを /usr/local/bin/hello-logger.sh として作ります。
# スクリプトを作成 sudo tee /usr/local/bin/hello-logger.sh << 'EOF' #!/bin/bash while true; do echo "$(date '+%Y-%m-%d %T') [hello-logger] alive" sleep 5 done EOF # 実行権限を付ける sudo chmod 755 /usr/local/bin/hello-logger.sh
systemd に預ける前に、手で動かして確かめておきます。
/usr/local/bin/hello-logger.sh
5 秒ごとに時刻付きの行が出れば成功です。Ctrl + C で止めてください。止めないと次の手順に進めません。
ここで確認していること: サービス化したあとに動かないとき、原因が「スクリプト自体」なのか「systemd への登録」なのかを切り分けられなくなります。先に素の状態で動くことを見ておくと、あとの調査が一段楽になります。
STEP 03 · ユニットファイルを書く
/etc/systemd/system/hello-logger.service を作ります。§03 で見た 3 セクションの形です。
sudo tee /etc/systemd/system/hello-logger.service << 'EOF'
[Unit]
Description=Hello Logger - 演習用タイムスタンプ記録サービス
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/hello-logger.sh
Restart=on-failure
RestartSec=5s
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
ExecStart=には絶対パスを書く: systemd はあなたのシェルとは別の環境でプロセスを起動するため、PATHが同じとは限りません。hello-logger.shではなく/usr/local/bin/hello-logger.shと、必ずフルパスで書いてください。相対パスで書くと起動に失敗します。
STEP 04 · systemd に読み込ませて起動する
ユニットファイルを systemd に認識させてから、サービスを起動します。
# ユニットファイルの追加・変更を反映する sudo systemctl daemon-reload # 「今すぐ起動」と「次回から自動起動」を同時に設定 sudo systemctl enable --now hello-logger # 状態を確認 systemctl status hello-logger
● hello-logger.service - Hello Logger - 演習用タイムスタンプ記録サービス
Loaded: loaded (/etc/systemd/system/hello-logger.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-07-28 09:59:34 JST; 17ms ago
Main PID: 2792 (hello-logger.sh)
Tasks: 2 (limit: 2255)
Memory: 596.0K (peak: 780.0K)
CPU: 3ms
見るところは 2 か所です。Active: 行が active (running) であること、そして Loaded: 行の末尾に enabled と出ていること。この enabled が「次回も起き上がる」という申告です。
# 自動起動の設定だけを 1 行で確認する systemctl is-enabled hello-logger
enabled
ここまでで「設定は入った」状態です。本当に効くかどうかは STEP ⑥ 以降で確かめます。
STEP 05 · 壊す(1)── プロセスを強制終了して Restart= を見る
まず小さいほうの復活を見ます。kill -9 でプロセスを叩き落とし、Restart=on-failure が拾ってくれるかを観察します。
# いまのメインプロセス ID を控える systemctl status hello-logger | grep "Main PID" # 強制終了(異常終了させる) sudo kill -9 $(systemctl show hello-logger --property MainPID | cut -d= -f2) # RestartSec=5s の待機ぶん待ってから確認 sleep 6 systemctl status hello-logger
● hello-logger.service - Hello Logger - 演習用タイムスタンプ記録サービス
Loaded: loaded (/etc/systemd/system/hello-logger.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-07-28 09:59:47 JST; 989ms ago
Main PID: 2867 (hello-logger.sh)
7月 28 09:59:42 learner01 systemd[1]: hello-logger.service: Failed with result 'signal'.
7月 28 09:59:47 learner01 systemd[1]: hello-logger.service: Scheduled restart job, restart counter is at 1.
7月 28 09:59:47 learner01 systemd[1]: Started hello-logger.service - Hello Logger - 演習用タイムスタンプ記録サービス.
Main PID が変わっていることに注目してください(例では 2792 → 2867)。同じサービスですが、中身のプロセスは別物に入れ替わっています。restart counter is at 1 が「1 回目の再起動をやった」という systemd の申告です。
systemctl stopとの違い:systemctl stopでサービスを止めた場合、Restart=on-failureがあっても再起動しません。こちらは「正常な停止」だからです。on-failureが反応するのは異常終了(killシグナルや 0 以外の終了コード)に限られます。止めたいのに勝手に起き上がると感じたときは、この違いを思い出してください。
STEP 06 · 壊す(2)── Proxmox から電源を落とす
この章の核心です。Proxmox ホストから VM の電源そのものを落とします。OS のシャットダウン処理を挟まない、コンセントを抜くのに近い操作です。
workstation01 で別のターミナルを開いて、Proxmox ホストに接続してください。<Proxmox管理IP> は受講環境の案内に記載された IP に読み替えます。
# 別ターミナルで Proxmox ホストに接続 ssh ops@<Proxmox管理IP> # VMID を確認(左端の数字) qm list | grep learner01 # learner01 を停止する(電源断相当) qm stop <VMID>
qm stop は成功しても何も出力しません。代わりに、さきほどまで使っていた learner01 のターミナルが切れます(Connection to learner01 closed. と出るか、無反応になります)。これが電源が落ちた合図です。
# 本当に止まったかを確認 qm status <VMID> # 電源を入れ直す qm start <VMID>
status: stopped (qm start の標準出力なし)
ここで「起きるはずのないこと」を確認しています: 電源が落ちた時点で、
Restart=on-failureの面倒を見る systemd 自身も消えています。次にhello-loggerが動いていたとしたら、それはRestart=ではなく OS の起動手順に組み込まれていたからとしか説明がつきません。
STEP 07 · 戻る ── 自動起動していることを確かめる
qm start からおよそ 20〜30 秒待ってから、workstation01 の元のターミナルで learner01 に接続し直します。
# 再接続 ssh ops@learner01 # 自分で起き上がっているか systemctl is-active hello-logger
active
この active の 1 行が、enable が効いていた証拠です。誰も start を打っていないのに、OS が起動の途中で hello-logger を立ち上げました。
# いつ起動したのかも見る systemctl status hello-logger
● hello-logger.service - Hello Logger - 演習用タイムスタンプ記録サービス
Loaded: loaded (/etc/systemd/system/hello-logger.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-07-28 10:00:19 JST; 2min 16s ago
Main PID: 1084 (hello-logger.sh)
Tasks: 2 (limit: 2255)
Memory: 748.0K (peak: 1.3M)
CPU: 61ms
Main PID にも注目してください。STEP ⑤ では 2867 でしたが、ここでは 1084 と小さい数字に戻っています。PID は OS が起動してから順に振られるので、小さい PID は「起動直後に立ち上がった」印です。OS ごと作り直されたことがここにも表れています。
systemctl is-active hello-logger が active を返し、かつ systemctl status の since(起動時刻)が qm start の後の時刻になっていること。STEP 08 · 章末クリーンアップ
この演習で作ったものをすべて撤去し、演習前の状態に戻します。
# サービスを止めて、自動起動も解除する sudo systemctl disable --now hello-logger
Removed "/etc/systemd/system/multi-user.target.wants/hello-logger.service".
この出力が enable の正体です。enable は multi-user.target.wants/ というディレクトリにシンボリックリンクを 1 本張るだけの操作でした。OS はこのディレクトリの中身を見て「起動時に何を立ち上げるか」を決めています。
# ユニットファイルとスクリプトを削除 sudo rm /etc/systemd/system/hello-logger.service sudo rm /usr/local/bin/hello-logger.sh # 削除を systemd に反映 sudo systemctl daemon-reload # 残骸がないことを確認 systemctl status hello-logger
Unit hello-logger.service could not be found. と出れば完了です。これはエラーではなく「もう無い」という意味なので、赤い文字が出ても心配いりません。
| 確認項目 | 期待値 |
|---|---|
systemctl status hello-logger | Unit hello-logger.service could not be found. |
/etc/systemd/system/hello-logger.service | 存在しない(ls で確認) |
/usr/local/bin/hello-logger.sh | 存在しない |
| 電源断テストの結果 | 演習中に is-active = active を確認済み |
詰まったら
- ハマりポイント: よくある詰まりと対処を以下に列挙しています
- AI に相談: 演習中の疑問を章の内容を踏まえて AI に聞けます
ハマりポイント
STEP ④ で Active: failed になる
まず journalctl -u hello-logger -n 20 で直近のログを見てください。原因の大半は次の 2 つです。
①スクリプトに実行権限がない: ls -l /usr/local/bin/hello-logger.sh で -rwxr-xr-x になっているか確認します。なっていなければ sudo chmod 755 を実行し直してください。
②ExecStart= のパスが違う: 相対パスやタイプミスがないか確認します。systemctl cat hello-logger で、systemd が実際に読み込んでいる内容を見られます。
ユニットファイルを直したのに、動きが変わらない
sudo systemctl daemon-reload を忘れている可能性が高いです。systemd はファイルの変更を自動では検知しません。ユニットファイルを触ったら必ず daemon-reload、と覚えてください。
systemctl status の Loaded: 行に changed on disk のような警告が出ていれば、まさにこの状態です。
STEP ⑦ で SSH がつながらない
Connection refused の場合: VM の起動がまだ終わっていません。qm start から 20〜30 秒待ってから再試行してください。
Connection timed out during banner exchange の場合: ping も通り、ポート 22 も開いているのにこれが出ることがあります。sshd がまだ応答を返し始めていない状態です。1〜2 分待ってから再試行してください。ポートが開いていることと、サービスが応答を始めていることは別です。
上記以外の詰まりと対処を一覧にまとめます。
| 起きたこと | 対処 |
|---|---|
④ daemon-reload 後に Failed to load unit file | ユニットファイルの書式エラー。systemctl status hello-logger に該当行が出るので、STEP ③ のファイルを修正してから daemon-reload をやり直す |
④ is-enabled が disabled になる | enable --now ではなく start だけを実行した可能性。sudo systemctl enable hello-logger を実行する |
⑤ kill -9 の後に再起動しない | RestartSec=5s の待ち時間を過ぎているか確認(sleep 6 を挟む)。それでも戻らなければ systemctl status でエラーを読む |
| ⑥ Proxmox に SSH できない | <Proxmox管理IP> が受講環境案内の値と一致しているか確認。proxmox というホスト名では解決できない(workstation01 の /etc/hosts に登録されていないため) |
⑦ is-active が inactive になる | systemctl is-enabled hello-logger を確認。disabled なら STEP ④ の enable が漏れている(この場合は演習として正しく「失敗を観測できた」状態) |
クリーンアップ後に systemctl status がエラーを出す | Unit ... could not be found. は正常。「存在しない」という意味でありエラーではない |
AI に相談
修了確認
この章で体験した「2 つの復活」の違いを確認します。
問 1 · enable と start の違い
systemctl start hello-logger と systemctl enable hello-logger の違いを説明してください。また、qm stop → qm start(電源断相当)の後にサービスが自動で起き上がったのは、どちらの効果ですか?
解答を見る
| コマンド | 効果 | 再起動後 |
|---|---|---|
systemctl start | 今すぐプロセスを起動する | 消える(一時的) |
systemctl enable | 次回起動時から自動起動する設定を入れる | 起き上がる(永続的) |
電源断後に自動起動したのは enable(WantedBy=multi-user.target)の効果です。start だけでは、電源を入れ直すたびに人がコマンドを打つ必要があります。
enable --now は「今すぐ起動(start)」と「次回から自動起動(enable)」を 1 コマンドでまとめて行う形です。実務ではこれを使う場面が最も多くなります。
問 2 · Restart= と enable の守備範囲
今回書いたユニットファイルの Restart=on-failure と WantedBy=multi-user.target は、それぞれ何を制御していますか? また、電源断の後に効くのはどちらで、それはなぜですか?
解答を見る
| 設定 | 制御する対象 |
|---|---|
Restart=on-failure | 同じ OS セッションの中で、プロセスが異常終了したときに自動再起動する。kill -9 や 0 以外の終了コードで発動する |
WantedBy=multi-user.target | OS が multi-user.target フェーズに達したときに、このサービスを起動する。systemctl enable の実体は、この設定をシンボリックリンクで有効化する操作 |
電源断の後に効くのは enable(WantedBy=)です。理由は、電源が落ちた時点で systemd 自身も一度死んでいるからです。Restart= は「動いている systemd が、死んだ子プロセスを拾い直す」仕組みなので、systemd ごと消えてしまえば誰も拾えません。
電源を入れ直すと、OS は起動手順の中で multi-user.target.wants/ の中身を読み、そこに置かれたサービスを立ち上げます。STEP ⑧ で disable したときに表示された Removed "/etc/systemd/system/multi-user.target.wants/hello-logger.service". が、まさにその仕掛けです。
段階ヒント(問 1・問 2 共通)
段階ヒント 1 段目:systemd は「書く → 読ませる → 有効にする」
systemd の操作はこの 3 ステップの順序を守れば迷いません。ファイルを書く → daemon-reload で読ませる → enable / start で動かす。ユニットファイルを編集したら必ず daemon-reload を先に実行してください(忘れると古い設定のまま動き続けます)。状態の確認は常に systemctl status <svc> から始めると、原因が Loaded: 行や Process: 行に出ています。
段階ヒント 2 段目:具体的なコマンド手順
# スクリプトに実行権限(STEP ② の tee の後) sudo chmod 755 /usr/local/bin/hello-logger.sh # ユニットファイルを読ませる(STEP ③ の tee の後) sudo systemctl daemon-reload # 今すぐ起動+次回から自動起動 sudo systemctl enable --now hello-logger systemctl status hello-logger # active (running) を確認 systemctl is-enabled hello-logger # enabled を確認
よくある落とし穴:
daemon-reloadを忘れる → 古い設定のまま動く(statusのLoaded:行で気づける)ExecStart=に相対パスを書く → 起動できずfailedになる
答えを見る(フルコマンド列)
# ── learner01(ops)── sudo chmod 755 /usr/local/bin/hello-logger.sh sudo systemctl daemon-reload sudo systemctl enable --now hello-logger systemctl status hello-logger # active (running) systemctl is-enabled hello-logger # enabled # Restart= の確認 sudo kill -9 $(systemctl show hello-logger --property MainPID | cut -d= -f2) sleep 6 systemctl is-active hello-logger # active(Restart=on-failure で復帰) # ── Proxmox ホスト(別ターミナル)── qm list | grep learner01 # VMID 確認 qm stop <VMID> # 電源断相当 qm status <VMID> # stopped qm start <VMID> # 再投入 # ── workstation01(20〜30 秒後)── ssh ops@learner01 systemctl is-active hello-logger # active ← enable が効いた証拠 # ── クリーンアップ(learner01)── sudo systemctl disable --now hello-logger sudo rm /etc/systemd/system/hello-logger.service sudo rm /usr/local/bin/hello-logger.sh sudo systemctl daemon-reload systemctl status hello-logger # could not be found.
このフローで覚えること:
enableは「次回起動時から自動起動する」宣言、startは「今すぐ起動する」命令。両方いるRestart=はセッション内の異常終了に効き、enableは電源断の後に効く。別の仕組み- ユニットファイルを触ったら必ず
daemon-reloadを先に
次の章へ
この章では「サービスを常駐させる」ことを扱いました。次の Chapter 2 では、そのサービスがおかしくなったときに原因を追う技術を扱います。systemd は全サービスのログを journal という 1 か所に集めています。次章では本章で作ったサービスをわざと壊し、journalctl で失敗を追跡し、修正し、さらに電源イベントをまたいだログまで読みます。
journalctl -u <svc>でサービス単位にログを絞り込む- 失敗したサービスのログから原因を特定し、直して復旧させる
- 再起動をまたいだログを読み、「いつ落ちたか」を時系列で追う
もっと知りたい方へ
systemctl list-units --all: 起動中だけでなく、停止中・失敗中も含むすべてのユニットを見る。--type=serviceと組み合わせると絞り込めますsystemd-analyze blame: 起動時に各サービスが何秒かかったかを一覧表示します。「起動が遅い」の原因を探るときの入口ですsystemctl cat hello-logger: いま systemd が認識しているユニットファイルの中身を表示します。daemon-reload漏れを疑うときに、ファイルの中身と突き合わせられますType=oneshot:Type=simpleは「起動したら動き続ける」サービス用です。oneshotはコマンドが終わったら完了とみなす「1 回限りの処理」用(バックアップスクリプトや初期化処理など)- systemd タイマー:
cronの代わりに systemd で定期実行する仕組みです。hello-logger.timerを作ると、cronより細かいスケジュール指定と journal 連携ができます - ドロップイン設定(
<svc>.service.d/override.conf): 既存のユニットファイルを直接編集せず、一部だけを上書きする方法です。パッケージが配布するユニットを壊さずに調整できます - Part 5 への伏線: 本章の
qm stop/qm startは Proxmox の電源操作の最も基本的な形です。Part 5「仮想化と Proxmox」では、WoL(Wake on LAN)・スナップショットと組み合わせた電源管理を扱います