結論

systemd は Linux の起動とサービス(常駐プログラム)を管理する仕組みで、systemctl はその systemd に「起動して」「止めて」「自動起動にして」と頼むコマンドです。まず systemctl status サービス名 で状態とログの末尾を見て、start・stop・restart・enable を使い分けます。

この記事でわかること

  • status の出力の読み方と、start・restart・reload・enable の違い(止まる時間の実測つき)
  • 自作サービスの unit ファイル・timer の書き方と、実際に動かした結果
  • failed になったときの切り分けと、よくあるエラー17種の原文

2026年10月29日更新|systemd 255(Ubuntu 24.04)を PID 1 として起動して実行確認

systemctl は、systemd という「サービスの管理役」に指示を出す窓口です。コマンドを打つと、systemd が unit ファイル(サービスの設定書)を読み、プロセスを起動・停止し、ログは journald に集まります。

flowchart TD
    U[systemctl start hello] --> D[systemd PID 1]
    F[unit ファイル<br>hello.service] --> D
    D --> P[プロセスを起動<br>cgroup で管理]
    P --> J[journald にログ]
    J --> K[journalctl -u hello]

よく調べられることの答えを先にまとめます。

知りたいこと 答え 詳しい節
systemd とは PID 1 として動き、サービス・マウント・タイマーなどを「ユニット」として管理する仕組み systemdとは
systemctl status の見方 Loaded(設定と自動起動)・Active(今の状態)・Main PID・末尾のログを見る statusの見方
restart と reload の違い restart は止めて起動し直す。reload はプロセスを止めずに設定だけ読み直させる start・stop・restart・reload
自動起動の設定 systemctl enable --now 名前(今すぐ起動も同時に) enable・disable
unit ファイルを書き換えた systemctl daemon-reload のあと restart systemctl edit と daemon-reload
サービスのログを見る journalctl -u 名前 -n 50、追いかけるなら -f journalctl
failed になった status の Process 行の終了コード→journalctl→reset-failed の順 failedの切り分け
cron の代わりに定期実行 .service と .timer を組で作り、enable --now 名前.timer systemd timer
service コマンドとの違い Ubuntu の service は systemd があれば systemctl を呼ぶ serviceコマンド・SysVinit

確認環境:Ubuntu 24.04.5 LTS(カーネル 6.18)のコンテナで確かめました。このコンテナの PID 1 は systemd ではないため、systemd 255(255.4-1ubuntu8.18)を、unshare で作った PID・マウント・UTS・IPC・cgroup の名前空間と専用のネットワーク名前空間の中で PID 1 として起動しました。ファイルシステムは overlay で重ね、変更はすべて作業用の場所に書いています(ホストの systemd と設定には触れていません)。この中で、自作の Web アプリ(Python 3.13.18 の http.server)を hello.service として動かし、start・stop・restart・reload・enable・disable・edit・mask、Restart= による自動再起動、起動回数の上限、わざと失敗させた unit 9種、timer と systemd-run、systemctl --user を実行し、出力をそのまま載せています。疎通は curl 8.5.0 で 127.0.0.1 に送りました。電源操作(reboot・poweroff)、target の切り替え(isolate・rescue)、リモート操作(-H)、WSL での有効化は、systemd の公式マニュアル(freedesktop.org)と Microsoft Learn で確かめた範囲だけを書いています。図は mermaid 11.16.0 で描画を確かめました(確認日 2026年10月29日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「systemctlコマンドの使い方とsystemdとは|statusとエラー原文」

systemdとは・systemctlとは(PID 1とユニット)

この節では、systemd と systemctl の関係と、「ユニット」という考え方が分かります。

systemd は、Linux で最初に起動するプロセス(PID 1)として動き、ほかのプログラムの起動・停止・再起動・ログを管理するソフトウェアです。 Ubuntu・Debian・RHEL・Fedora など主な Linux ディストリビューションで、以前の SysVinit(/etc/init.d のスクリプトで起動する方式)に代わって標準になっています。systemctl は systemd を操作するためのコマンドで、systemd 本体ではありません。

systemd は管理する対象をユニットと呼び、種類を拡張子で表します。今回の環境で読み込まれていた 160 個のユニットを種類別に数えると、次のようになりました(systemctl list-units --all)。

拡張子 何を管理するか この環境の数
.service常駐プログラム・1回だけの処理(Web サーバー、DB、バッチ)73
.targetユニットのまとまり。以前のランレベルにあたる(multi-user.target など)40
.mountファイルシステムのマウント21
.socket接続が来たらサービスを起動する待ち受け11
.slicecgroup の階層(CPU・メモリの区切り)4
.timer決まった時刻・間隔でサービスを起動する(cron の代わり)3
.pathファイルの変化を見張ってサービスを起動する2

サービスの .service は省略でき、timer などは backup.timer のように拡張子を付けます。

systemd(管理役)

PID 1 として常に動いている

unit ファイルを読んでプロセスを起動・監視

落ちたら Restart= に従って起動し直す

systemctl(指示を出すコマンド)

打ったときだけ動いて終わる

D-Bus・専用ソケット経由で systemd に頼む

systemd が PID 1 でないと使えない

PID 1 が systemd ではない環境(Docker のコンテナ・設定前の WSL)では、次のように断られます(今回のコンテナで実行。終了コード 1)。

$ systemctl status cron
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

systemctlコマンド一覧(よく使う20個)

この節では、systemctl のサブコマンドを目的別に一覧で確かめられます。

書式は systemctl サブコマンド ユニット名 です。状態を変える操作には root 権限が要るため、一般ユーザーは sudo を付けます。

やりたいこと コマンド メモ
状態とログの末尾を見るsystemctl status hello権限なしで見られる
起動するsystemctl start hello起動済みなら何もしない
止めるsystemctl stop helloSIGTERM→時間切れで SIGKILL
止めて起動し直すsystemctl restart hello止まっていれば起動する
設定だけ読み直させるsystemctl reload helloExecReload= がある時だけ
reload できなければ restartsystemctl reload-or-restart helloスクリプト向き
動いている時だけ restartsystemctl try-restart hello止まっていれば何もしない
自動起動にする(今も起動)systemctl enable --now hello--now なしは次の起動から
自動起動をやめる(今も停止)systemctl disable --now hello
起動できなくするsystemctl mask hello戻すのは unmask
動いているかsystemctl is-active hello終了コードで判定できる
自動起動かsystemctl is-enabled hello
失敗したユニットsystemctl --failedlist-units --failed と同じ
サービス一覧systemctl list-units --type=service読み込み済みのもの
unit ファイル一覧systemctl list-unit-filesenabled・disabled が分かる
設定の中身を見るsystemctl cat helloドロップインも順に表示
設定値を1つ見るsystemctl show hello -p MainPIDスクリプト向き
設定を部分的に上書きsystemctl edit hello保存すると自動で再読み込み
unit ファイルを読み直すsystemctl daemon-reloadファイルを直接編集した後
失敗の記録を消すsystemctl reset-failed hello起動回数の上限も戻る

電源操作の reboot・poweroff、SSH 経由で別のマシンを操作する -H ユーザー@ホスト もあります(公式マニュアルで確認。今回は実行していません)。

systemctl statusの見方(出力を1行ずつ読む)

この節では、systemctl status の出力のどこを見れば、動いているか・自動起動か・なぜ止まったかが分かるのかが分かります。

自作の hello.service を起動した直後の status です。

$ systemctl status hello
● hello.service - Hello sample web app (t151)
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; preset: enabled)
     Active: active (running) since Fri 2026-10-30 14:44:43 UTC; 564ms ago
   Main PID: 296 (python3)
      Tasks: 1 (limit: 9607)
     Memory: 8.7M ()
     CGroup: /system.slice/hello.service
             └─296 /usr/bin/python3 -u /opt/hello/app.py

Oct 30 14:44:43 vm systemd[1]: Started hello.service - Hello sample web app (t151).
Oct 30 14:44:43 vm python3[296]: listening on 127.0.0.1:8151
Oct 30 14:44:44 vm python3[296]: access: "GET / HTTP/1.1" 200 -
行 読み方 この例では
先頭の記号● 緑=動作中、○=止まっている、× 赤=失敗● 動作中
Loadedunit ファイルの場所; 自動起動の設定; ディストリビューションの既定(preset)/etc/systemd/system に置いた自作。自動起動はしない
Drop-In部分上書きのファイル(あるときだけ表示)なし
Active今の状態(括弧の中が詳しい状態)と、いつからか564ms 前から動作中
Main PID本体のプロセス番号296 の python3
Process終わったプロセスと終了コード(失敗時に出る)なし
CGroupこのサービスに属するプロセスの木1つだけ
末尾のログjournald に集まった直近10行起動とアクセスの記録

Active に出る状態は、次の5つを覚えれば読めます。

1

active (running)

常駐プログラムが動いている。

● 緑

2

active (exited)

1回だけの処理が成功して終わった(Type=oneshot と RemainAfterExit=yes)。

止まっているが正常

3

inactive (dead)

止まっている。起動していない、または正常に止めた。

○

4

activating (auto-restart)

落ちたので、RestartSec= の間待ってから起動し直すところ。

再起動待ち

5

failed

失敗して止まった。Result: の後ろに理由(exit-code・timeout・start-limit-hit など)。

× 赤

status は、ページャー(less)で表示されて止まることがあります。 スクリプトや貼り付け用には --no-pager を付け、ログの行数は -n 30 のように変えます。行が右で切れるときは -l(全文表示)を付けます。

start・stop・restart・reloadの違い(止まる時間を実測)

この節では、4つの操作が何をするかと、restart と reload で利用者から見た止まり方がどう違うかが分かります。

hello.service は、/etc/hello/message.txt の文言を返す小さな Web アプリです。SIGHUP を受けると文言を読み直すように作り、unit ファイルに ExecReload=/bin/kill -HUP $MAINPID を書きました。文言を「Hello v2」に変えて reload と restart を続けて実行した結果です。

$ echo "Hello v2" > /etc/hello/message.txt
$ systemctl reload hello
$ curl -s http://127.0.0.1:8151/
Hello v2 (pid=174 GREETING=from-EnvironmentFile)
$ systemctl restart hello
$ curl -s http://127.0.0.1:8151/
Hello v2 (pid=187 GREETING=from-EnvironmentFile)

reload のあとは pid=174 のまま文言だけが変わり、restart のあとは pid=187 に変わりました。 reload はプロセスを止めず、restart は止めて新しいプロセスを起動します。

では、利用者から見てどれだけ止まるのか。20ms おきに curl で問い合わせながら、途中で restart と reload を1回ずつ実行しました(3秒間)。

5回restart 中に失敗した問い合わせ成功 61回。待ち受けが一度閉じる
0回reload 中に失敗した問い合わせ成功 119回。プロセスはそのまま
37mssystemctl restart が返るまで5回の中央値。20〜189ms
操作 プロセス 止まっていたら 向いている場面
start新しく起動起動する止まっているサービスを動かす
stopSIGTERM で止める(応答が無ければ既定90秒後に SIGKILL)何もしない作業のために止める
restart止めて新しく起動(PID が変わる)起動するプログラムの更新・unit ファイルの変更後
reloadそのまま(ExecReload= を実行)エラーnginx・sshd などの設定ファイルを変えた後

reload は、ExecReload= が書かれているサービスだけで使えます。止まっているサービスに reload を送ると hello.service is not active, cannot reload. と断られました。どちらか迷うスクリプトでは reload-or-restart を使います。

短い間に restart を繰り返さない

やってはいけないデプロイのスクリプトで、確認のために restart を 0.3 秒おきに6回打つ。今回は6回目で Start request repeated too quickly. と出て failed(start-limit-hit)になった
→
代わりにrestart は1回にして、状態は systemctl is-active で確かめる。間隔を2.2秒あけた5回は問題なく通った

既定では10秒間に5回まで(StartLimitIntervalSec=10s・StartLimitBurst=5。systemctl show で表示された値)

enable・disableで自動起動を設定する(--now・mask)

この節では、OS の起動時にサービスを自動で動かす設定と、その中身(シンボリックリンク)が分かります。

enable は「次に OS が起動したときに動かす」設定で、今すぐ起動はしません。 今すぐ起動もしたいときは --now を付けます。

$ systemctl enable hello
Created symlink /etc/systemd/system/multi-user.target.wants/hello.service → /etc/systemd/system/hello.service.
$ systemctl is-enabled hello
enabled
$ systemctl disable hello
Removed "/etc/systemd/system/multi-user.target.wants/hello.service".

$ systemctl stop hello
$ systemctl enable --now hello
Created symlink /etc/systemd/system/multi-user.target.wants/hello.service → /etc/systemd/system/hello.service.
$ systemctl is-active hello
active

出力のとおり、enable の正体は multi-user.target.wants というフォルダーにシンボリックリンクを置くことです。unit ファイルの [Install] にある WantedBy=multi-user.target がリンクを置く場所を決めています。[Install] が無い unit は enable できず、list-unit-files で static(ほかのユニットから呼ばれて動く)と表示されます。

mask:手動でも起動できなくする

disable は自動起動をやめるだけで、systemctl start や依存関係からは起動できます。どうしても起動させたくないときは mask を使います。redis-server で試しました。

$ systemctl mask redis-server
Created symlink /etc/systemd/system/redis-server.service → /dev/null.
$ systemctl start redis-server
Failed to start redis-server.service: Unit redis-server.service is masked.
$ systemctl unmask redis-server
Removed "/etc/systemd/system/redis-server.service".

mask は /etc/systemd/system に /dev/null へのリンクを置く仕組みなので、自分で /etc/systemd/system に置いた unit には使えません。hello.service に mask を打つと、次のように断られました。

$ systemctl mask hello
Failed to mask unit: File /etc/systemd/system/hello.service already exists.

is-active・is-enabled・is-failedと終了コード

この節では、シェルスクリプトや監視でサービスの状態を判定する方法と、終了コードの意味が分かります。

is-active などは、状態を1語で表示し、終了コード($?)でも結果を返します。表示を消すなら --quiet を付けます。

$ systemctl is-active hello; echo "exit=$?"
active
exit=0
$ systemctl is-enabled hello; echo "exit=$?"
disabled
exit=1
$ systemctl is-failed hello; echo "exit=$?"
active
exit=1
$ systemctl status helo; echo "exit=$?"
Unit helo.service could not be found.
exit=4
終了コード status・is-active での意味 今回の例
0動いている(active)動作中の status・is-active
1is-failed で「失敗ではない」、is-enabled で「自動起動ではない」disabled のとき
3動いていない(inactive・failed)止めた後・失敗後の status
4そのユニットが無い名前を打ち間違えた helo

この番号は LSB(以前の init スクリプトの決まり)の値で、公式マニュアルは状態の文字列を直接見ることを勧めています。監視では systemctl is-active --quiet hello || 通知する の形が使いやすく、詳しい状態は systemctl show hello -p ActiveState -p SubState -p Result で取ります。

システム全体の状態は systemctl is-system-running で分かります。今回、失敗したユニットが6個残っている間は degraded(終了コード1)、systemctl reset-failed で記録を消すと running に戻りました。

list-units・list-unit-files・list-dependenciesで一覧を見る

この節では、サービスの一覧と、自動起動の設定・依存関係の見方が分かります。

2つの一覧は対象が違います。list-units は「今メモリに読み込まれているユニット」、list-unit-files は「ディスクにある unit ファイル」です。自動起動の設定を見るなら list-unit-files を使います。

$ systemctl list-unit-files --type=service
UNIT FILE                                    STATE           PRESET
hello.service                                disabled        enabled
postgresql.service                           disabled        enabled
postgresql@.service                          indirect        enabled
redis-server.service                         enabled         enabled
redis.service                                alias           -
(略)

STATE 欄の値は、今回の環境(unit ファイル 274 個)では次の割合でした。

STATE 意味 件数
static[Install] が無い。ほかから呼ばれて動く。enable できない184
disabled自動起動しない55
alias別名(redis.service → redis-server.service など)15
masked起動できなくしてある10
indirectテンプレート(名前@.service)など、間接的に有効3
enabled自動起動する3

絞り込みは --type=service・--state=running・--state=failed・--all が便利です。

依存関係は list-dependencies で木の形に表示されます。--reverse を付けると「このユニットに頼っている側」が出ます。

$ systemctl list-dependencies app-req
app-req.service
○ ├─demo-db.service
● ├─system.slice
● └─sysinit.target
●   ├─dev-hugepages.mount
(略)
$ systemctl list-dependencies --reverse demo-db
demo-db.service
● └─app-wants.service

自作サービスのunitファイルの書き方(Restart・依存・環境変数)

この節では、自分のプログラムを systemd のサービスにする unit ファイルの書き方と、各項目が実際にどう効くかが分かります。

自作の unit ファイルは /etc/systemd/system/名前.service に置きます。パッケージが入れる unit は /usr/lib/systemd/system にあり、同じ名前なら /etc 側が優先されます。今回動かした hello.service の全文です。

[Unit]
Description=Hello sample web app (t151)
After=network.target

[Service]
Type=simple
EnvironmentFile=/etc/hello/hello.env
ExecStart=/usr/bin/python3 -u /opt/hello/app.py
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=2
User=hello

[Install]
WantedBy=multi-user.target
1

実行するユーザーを作る

useradd --system --no-create-home --shell /usr/sbin/nologin hello。root で動かさない。nobody を指定すると、検証で Special user nobody configured, this is not safe! と警告された。

User=

2

unit ファイルを置いて検証する

systemd-analyze verify /etc/systemd/system/hello.service。書き間違いや存在しない実行ファイルを、起動前に見つけられる。

起動前の確認

3

読み込ませる

systemctl daemon-reload。新しいファイルや変更を systemd に読み直させる。

ファイルを変えるたび

4

起動して確かめる

systemctl start hello のあと systemctl status hello と journalctl -u hello。Python は -u を付けないと出力がバッファーに溜まり、ログがすぐに出ない。

動作確認

5

自動起動にする

systemctl enable hello。動作を確かめてから有効にする。

最後に

Type=:起動完了をいつとみなすか

Type 起動完了とみなす時点 向いているもの
simple(既定)プロセスを作った直後前面で動き続けるプログラム
exec実行ファイルの起動に成功した時simple の代わり。起動失敗を start の結果に出したいとき
notifyプログラムが「準備できた」と通知した時sd_notify に対応したサーバー
forking起動したプロセスが子を残して終わった時自分でデーモンになる以前のプログラム
oneshot処理が終わった時バックアップなど1回だけの処理・timer から呼ぶもの

Type=simple では、実行ファイルが無くても systemctl start は成功(終了コード0)を返しました。 失敗は直後の status で分かります。Type=exec に変えると、同じ間違いで start が終了コード1を返しました。公式マニュアルにも「simple では実行ファイルを起動できなくても start は成功を報告する」と書かれています。

Type=simple:  $ systemctl start bad-exec   → exit=0(直後に status=203/EXEC で failed)
Type=exec:    $ systemctl start bad-exec2
Job for bad-exec2.service failed because the control process exited with error code.
See "systemctl status bad-exec2.service" and "journalctl -xeu bad-exec2.service" for details.
→ exit=1

Restart=:落ちたら起動し直す

アプリの /crash に問い合わせて、終了コード3でわざと落としました。Restart=on-failure と RestartSec=2 によって、落ちてから 2.18 秒後に新しいプロセス(PID 305)で起動し直されました。

14:44:49.826 python3[296]: crash requested
14:44:49.827 systemd[1]: hello.service: Main process exited, code=exited, status=3/NOTIMPLEMENTED
14:44:49.827 systemd[1]: hello.service: Failed with result 'exit-code'.
14:44:51.979 systemd[1]: hello.service: Scheduled restart job, restart counter is at 1.
14:44:52.006 systemd[1]: Started hello.service - Hello sample web app (t151).
Restart= 起動し直す場合 使いどころ
no(既定)しない落ちたら人が見るもの
on-failure0以外で終了・シグナル・タイムアウト・ウォッチドッグWeb アプリ・API の多く
on-abnormalシグナル・タイムアウト・ウォッチドッグ(終了コードは対象外)自分で異常終了コードを返すもの
always正常終了も含めて必ず止まっては困る常駐プログラム

何度も落ちると、10秒間に5回の上限で起動をあきらめます。RestartSec を 100ms にして7回落とすと、6回目で次のように止まりました。

hello.service: Scheduled restart job, restart counter is at 6.
hello.service: Start request repeated too quickly.
hello.service: Failed with result 'exit-code'.
Failed to start hello.service - Hello sample web app (t151).

この状態で systemctl start hello を打っても Job for hello.service failed because the control process exited with error code. と出て起動しません(メッセージは紛らわしいですが、ログには Start request repeated too quickly. が出ます)。systemctl reset-failed hello で記録を消すと、すぐに起動できました。

After=・Requires=・Wants=:依存関係

After= は「順番」、Requires= と Wants= は「一緒に起動するか」を決めます。両方書くのが基本です。DB 役の demo-db と、それに Requires= で頼る app-req、Wants= で頼る app-wants を作り、demo-db を止めました。

$ systemctl start app-req app-wants        → demo-db も一緒に起動
$ systemctl stop demo-db
$ systemctl is-active demo-db app-req app-wants
inactive
inactive
active

Requires= の app-req は一緒に止められ、Wants= の app-wants は動き続けました。 相手が止まったら自分も止まるべきなら Requires=、相手が無くても動けるなら Wants= を選びます。network.target は「ネットワークの設定が始まった」だけを意味し、つながったことは保証しません。接続後に起動したいときは network-online.target を After= と Wants= の両方に書きます。

Environment=・EnvironmentFile=:環境変数

環境変数は unit ファイルに Environment=KEY=値 で書くか、EnvironmentFile= で別ファイルから読みます。パスワードなどは unit ファイルに書かず、権限を絞った別ファイルに置きます。

ここで1つ、つまずきやすい動きを確かめました。hello.env に GREETING=from-EnvironmentFile を書いたまま、ドロップインで Environment=GREETING=from-drop-in を足して restart すると、アプリに届いた値は from-EnvironmentFile のままでした。同じ変数が両方にあるときは EnvironmentFile= の値が使われます。上書きしたいときは、EnvironmentFile= のファイル側を書き換えます。

systemctl editとdaemon-reloadで設定を変える

この節では、パッケージの unit ファイルを直接書き換えずに設定を変える方法(ドロップイン)と、daemon-reload が要る場面が分かります。

/usr/lib/systemd/system の unit ファイルは、パッケージの更新で上書きされます。 設定を変えるときは systemctl edit 名前 で「差分だけ」のファイル(ドロップイン)を作ります。保存先は /etc/systemd/system/名前.service.d/override.conf で、保存すると自動で daemon-reload されます。

edit を開くと、次のひな形がエディターに表示されました(後半は本体と既存のドロップインの内容がコメントで並びます)。

### Editing /etc/systemd/system/hello.service.d/extra.conf
### Anything between here and the comment below will become the contents of the drop-in file



### Edits below this comment will be discarded


### /etc/systemd/system/hello.service
# [Unit]
# Description=Hello sample web app (t151)
(略)

書くのは2つのコメントの間です。 下のコメントより後ろに書いた内容は捨てられます。ファイルの末尾に追記するエディター操作をしたところ、エラーも出ずにドロップインが作られませんでした。間に書いて保存すると Successfully installed edited file '/etc/systemd/system/hello.service.d/extra.conf'. と表示されました。

コマンド 作られるもの 元に戻す
systemctl edit hellohello.service.d/override.conf(差分)systemctl revert hello
systemctl edit --drop-in=名前 hellohello.service.d/名前.conf同上
systemctl edit --full hello/etc に本体の写し(全文を置き換え)同上
systemctl edit --runtime hello/run に置く(再起動で消える)再起動

systemctl revert hello を実行すると、ドロップインがすべて消えました。

$ systemctl revert hello
Removed "/etc/systemd/system/hello.service.d/exec.conf".
Removed "/etc/systemd/system/hello.service.d/extra.conf".
Removed "/etc/systemd/system/hello.service.d/hardening.conf".
Removed "/etc/systemd/system/hello.service.d/override.conf".
Removed "/etc/systemd/system/hello.service.d".

ExecStart= を変えるときは空の行を先に書く

ドロップインに ExecStart= を1行だけ書くと、本体の ExecStart= に「追加」されて2つになり、起動を断られました。

Failed to restart hello.service: Unit hello.service has a bad unit file setting.
hello.service: Service has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.

先に空の ExecStart= を書いて一覧を消してから、新しい値を書きます。

[Service]
ExecStart=
ExecStart=/usr/bin/python3 -u /opt/hello/app.py

daemon-reload が要る場面

unit ファイルやドロップインをエディターで直接書き換えたときは、systemd がまだ前の内容を覚えています。この状態で status を見ると、先頭に次の警告が出ました。

Warning: The unit file, source configuration file or drop-ins of hello.service changed on disk. Run 'systemctl daemon-reload' to reload units.

systemctl daemon-reload は unit ファイルを読み直すだけで、動いているサービスは止めません。新しい設定でプロセスを動かすには、続けて restart します。daemon-reload(unit ファイルを読み直す)と reload(アプリに設定ファイルを読み直させる)は別物です。

journalctlでサービスのログを見る

この節では、systemd で動かしたサービスのログを journalctl で絞り込んで見る基本が分かります。

systemd のサービスが標準出力・標準エラーに書いた内容は、journald が集めます。ログファイルの場所を探さなくても、ユニット名で取り出せます。

$ journalctl -u hello --since "-2min" -n 3
2026-10-30T14:49:44+00:00 vm python3[2065]: access: "GET / HTTP/1.1" 200 -
2026-10-30T14:49:44+00:00 vm python3[2065]: access: "GET / HTTP/1.1" 200 -
2026-10-30T14:49:44+00:00 vm python3[2065]: access: "GET / HTTP/1.1" 200 -
やりたいこと コマンド
サービスのログ(新しい50行)journalctl -u hello -n 50
流れてくるログを追うjournalctl -u hello -f
今回の起動以降だけjournalctl -u hello -b
時間で絞るjournalctl -u hello --since "10 min ago"
警告以上だけjournalctl -p warning -b
失敗の説明つきで末尾へjournalctl -xeu hello

エラーメッセージで案内される journalctl -xeu の -x は説明文を足すオプションです。bad-user.service で実行すると、行ごとに次のような説明が付きました。

Oct 30 14:45:37 vm systemd[1]: bad-user.service: Main process exited, code=exited, status=217/USER
░░ Subject: Unit process exited
░░ Defined-By: systemd
░░
░░ An ExecStart= process belonging to unit bad-user.service has exited.
░░
░░ The process' exit code is 'exited' and its exit status is 217.

容量の管理や出力形式(JSON)など journalctl の詳しい使い方は、関連記事「journalctlの使い方|目的別コマンド逆引き一覧と絞り込み例」で扱っています。

systemd timerでcronの代わりに定期実行する

この節では、systemd の timer で決まった時刻・間隔に処理を動かす方法と、cron との違いが分かります。

timer は 実行する中身(.service)と、いつ動かすか(.timer)を同じ名前の2つのファイルに分けて書きます。毎日3時のバックアップの例です。

# /etc/systemd/system/backup.service
[Unit]
Description=nightly backup (sample)
[Service]
Type=oneshot
ExecStart=/bin/sh -c "tar -czf /var/tmp/hello-$(date +%%F).tgz /etc/hello && echo backup ok"

# /etc/systemd/system/backup.timer
[Unit]
Description=run backup daily at 03:00
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=10min
[Install]
WantedBy=timers.target

unit ファイルの中では % が特別な意味を持つため、date の書式は %%F と2つ重ねます。有効にするのは .service ではなく .timer です。

$ systemctl enable --now backup.timer
Created symlink /etc/systemd/system/timers.target.wants/backup.timer → /etc/systemd/system/backup.timer.
$ systemctl list-timers backup.timer
NEXT                        LEFT LAST PASSED UNIT         ACTIVATES
Sat 2026-10-31 03:02:41 UTC  12h -         - backup.timer backup.service
$ systemctl start backup.service        ← 時刻を待たずに今すぐ試す
$ journalctl -u backup.service -o cat
Starting backup.service - nightly backup (sample)...
tar: Removing leading `/' from member names
backup ok
backup.service: Deactivated successfully.
Finished backup.service - nightly backup (sample).

NEXT が 03:00 ではなく 03:02:41 なのは、RandomizedDelaySec=10min で0〜10分の範囲でずらしたためです。多くのサーバーが同時に動くのを避けるための設定です。

OnCalendar の書き方は systemd-analyze calendar で確かめる

$ systemd-analyze calendar --iterations=2 "Mon..Fri *-*-* 09:00:00"
Normalized form: Mon..Fri *-*-* 09:00:00
    Next elapse: Mon 2026-11-02 09:00:00 UTC
       From now: 2 days left
   Iteration #2: Tue 2026-11-03 09:00:00 UTC
$ systemd-analyze calendar "every day 9am"
Failed to parse calendar specification 'every day 9am': Invalid argument
動かしたい時 OnCalendar= cron で書くと
毎日0時daily(= *-*-* 00:00:00)0 0 * * *
平日の9時Mon..Fri *-*-* 09:00:000 9 * * 1-5
15分ごと*-*-* *:00/15:00*/15 * * * *
土日の3時半Sat,Sun 03:3030 3 * * 0,6
起動の5分後から1時間ごとOnBootSec=5min と OnUnitActiveSec=1h書けない

timer は「ちょうどその時刻」には動かない(実測)

systemd-run --on-active=2s で「2秒後に1回だけ」の一時的な timer を作り、実際に動いた時刻を測りました。

6.2〜11.5秒2秒後の予定が動いた時刻(既定)3回。AccuracySec の既定は1分
2.11秒AccuracySec=100ms を付けたとき--timer-property=AccuracySec=100ms
2.18秒RestartSec=2 で再起動までの時間再起動はほぼ指定どおり

timer は、CPU を起こす回数を減らすために、既定で最大1分の幅で実行をまとめます(AccuracySec=1min)。 秒単位で正確に動かしたいときは、.timer に AccuracySec=1s などを書きます。

1ログが journald に残る

cron はメールや自前のリダイレクトが要るが、timer なら journalctl -u backup で結果と終了コードが見られる。

2電源オフ中の分を取り戻せる

Persistent=true なら、止まっていた間に過ぎた回を起動後に1回動かす(OnCalendar= のときだけ)。

3二重に動かない

前の回の .service が動いている間は、次の回を重ねて起動しない。

cron の書式や落とし穴は、関連記事「cronの書き方|設定例30パターンの早見表と落とし穴まとめ」で扱っています。

failedになったときの切り分け手順

この節では、サービスが failed になったときに、どの順番で何を見れば原因に近づけるかが分かります。

わざと失敗させた unit の status は、次のようになりました。Process 行の status= を見るだけで、失敗の場所が分かれます。

わざと入れた間違い status の表示 journal に出た原文
ExecStart= のファイルが無いstatus=203/EXECMain process exited, code=exited, status=203/EXEC
User= のユーザーが無いstatus=217/USERFailed to determine user credentials: No such process
WorkingDirectory= のフォルダーが無いstatus=200/CHDIRChanging to the requested working directory failed: No such file or directory
ポートが使用中status=1/FAILUREOSError: [Errno 98] Address already in use
Type=forking なのに前面で動き続けるResult: timeoutstart operation timed out. Terminating.
10秒に6回落ちたResult: exit-code(手動の連打なら start-limit-hit)Start request repeated too quickly.

この環境では、203/EXEC のときに「どのファイルが無いか」を示す行は journal に出ませんでした。status の Process 行に ExecStart= の内容が出るので、そのパスを ls -l で確かめます。systemd-analyze verify なら bad-exec.service: Command /opt/hello/no-such-file is not executable: No such file or directory と、起動前にファイル名つきで教えてくれました。

ポートの使用中を調べる方法は関連記事「Address already in useの解決方法【Windows・Mac・Linux】」、プロセスの確かめ方と止め方は関連記事「Linuxプロセス確認と停止|ps・top・kill逆引きコマンド一覧」で扱っています。systemd で動かしているプロセスを kill で止めると、Restart= の設定によってはすぐ起動し直されます。止めるときは systemctl stop を使います。

よくあるエラーと直し方(原文つき)

この節では、systemctl を使っていて出るエラーの原文と、原因・直し方が一覧で分かります。すべて今回の環境で実際に出たものです。

エラーの原文 原因 直し方
System has not been booted with systemd as init system (PID 1). Can't operate.Docker のコンテナ・設定前の WSL など、PID 1 が systemd ではないコンテナではプログラムを直接起動する。WSL は wsl.conf で有効にする(よくある質問)
Failed to start helo.service: Unit helo.service not found.名前の打ち間違い・unit ファイルが無い・置き場所の違いsystemctl list-unit-files | grep 名前 で探す
Failed to restart hello.service: Interactive authentication required.一般ユーザーで状態を変えようとしたsudo を付ける
Failed to start redis-server.service: Unit redis-server.service is masked.mask されている意図を確かめて systemctl unmask
Failed to mask unit: File /etc/systemd/system/hello.service already exists./etc に置いた自作 unit を mask しようとしたdisable と stop を使う
Warning: The unit file, source configuration file or drop-ins of hello.service changed on disk.ファイルを直接編集して読み直していないsystemctl daemon-reload
Unit hello.service has a bad unit file setting.ドロップインで ExecStart= が2つになった など空の ExecStart= を先に書く
Unknown key name 'Descripton' in section 'Unit', ignoring.項目名の綴り違い(その行は無視されて起動はする)systemd-analyze verify で見つけて直す
Missing '=', ignoring line.= の無い行同上
Failed to parse service restart specifier, ignoring: sometimesRestart= に無い値no・on-failure・always などにする
Job for hello.service failed because the control process exited with error code.起動に失敗(起動回数の上限のときも同じ文言)status と journalctl -xeu を見る
Job for bad-timeout.service failed because a timeout was exceeded.起動完了の合図が来ない(Type の選び間違い・起動が遅い)Type= を見直す・TimeoutStartSec= を延ばす
hello.service: Start request repeated too quickly.10秒に5回を超えて起動した原因を直して reset-failed
hello.service is not active, cannot reload.止まっているサービスに reloadstart か reload-or-restart
Cannot edit units if not on a tty.スクリプトなど端末の無い所で systemctl editドロップインのファイルを直接置いて daemon-reload
Special user nobody configured, this is not safe!User=nobody(ほかのプログラムと共有のユーザー)専用のユーザーか DynamicUser=yes
Failed to parse calendar specification 'every day 9am': Invalid argumentOnCalendar= の書式違いsystemd-analyze calendar で試す

一般ユーザーで status は見られますが、start・stop・restart は断られます。サービス用のユーザーを作る手順と sudo の権限の付け方は、関連記事「Linuxユーザー追加とsudo権限付与|useradd手順と確認コマンド一覧」で扱っています。

ExecStart= に相対パスを書いたとき

systemd 255 では ExecStart=python3 /opt/hello/app.py のように名前だけでも起動できます。ただし探す場所は /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin の順で(systemd-path search-binaries-default で表示)、シェルの PATH とは違います。今回の環境では /usr/bin/python3 ではなく /usr/local/bin/python3 が使われました(ログのファイル名が /usr/local/lib/python3.13/ になっていた)。意図した版を確実に使うため、絶対パスで書きます。

安全のための設定(systemd-analyze security)

systemd-analyze security hello は、サービスに付けた制限を点数にします(10に近いほど制限が少ない)。hello.service は 9.2 UNSAFE でしたが、次のドロップインを足すと 3.5 OK になり、アプリはそのまま動きました。

[Service]
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictRealtime=yes
SystemCallArchitectures=native
CapabilityBoundingSet=
UMask=0077

ProtectSystem=strict は OS のファイルを読み取り専用にするため、書き込みが要るアプリは ReadWritePaths= で場所を足します。

serviceコマンド・SysVinitとの違いと判断表

この節では、以前の service・chkconfig・/etc/init.d との対応と、場面ごとにどのコマンドを使えばよいかが分かります。

Ubuntu の service コマンドは、systemd が動いていれば内部で systemctl を呼びます(/usr/sbin/service の中に exec systemctl $sctl_args ${ACTION} ${UNIT} の行がある)。service hello status を実行すると、systemctl status hello と同じ出力になりました。

やりたいこと 以前(SysVinit) systemd
起動・停止service hello start・/etc/init.d/hello stopsystemctl start hello
自動起動にするchkconfig hello on・update-rc.d hello enablesystemctl enable hello
一覧service --status-all・chkconfig --listsystemctl list-unit-files
ランレベルを変えるinit 3systemctl isolate multi-user.target
既定のランレベル/etc/inittabsystemctl get-default・set-default

ランレベルは target に置き換わり、互換の名前がリンクで残っています(/usr/lib/systemd/system/runlevel*.target)。今回の環境では、0→poweroff.target、1→rescue.target、2〜4→multi-user.target、5→graphical.target、6→reboot.target でした。

最後に、場面ごとの判断表です。

場面 使うもの 理由
nginx の設定を変えたsystemctl reload nginx接続を切らずに読み直せる
アプリを新しい版に入れ替えたsystemctl restartプロセスを新しくする必要がある
unit ファイルを直接直したdaemon-reload → restart読み直さないと前の設定のまま
パッケージの unit を少し変えたいsystemctl edit更新で上書きされない
デプロイのスクリプトで状態を判定is-active --quiet終了コードで分岐できる
毎日決まった時刻にバッチtimer(ログを残したい)か cron(手軽さ優先)timer は journal に残り、二重起動しない
一般ユーザーの常駐プログラムsystemctl --usersudo なしで管理できる
Docker のコンテナの中systemctl を使わないコンテナは1プロセスが基本。PID 1 が systemd ではない

systemctl --user:ユーザーごとのサービス

一般ユーザーは、~/.config/systemd/user に unit を置いて systemctl --user で自分のサービスを管理できます。ユーザー dev を作って試しました。

$ systemctl --user enable --now mytool
Created symlink /home/dev/.config/systemd/user/default.target.wants/mytool.service → /home/dev/.config/systemd/user/mytool.service.
$ systemctl --user status mytool
● mytool.service - user-level sample
     Loaded: loaded (/home/dev/.config/systemd/user/mytool.service; enabled; preset: enabled)
     Active: active (running) since Fri 2026-10-30 14:48:18 UTC; 8ms ago

ログアウト中も動かすには、root で loginctl enable-linger dev を実行します(今回はこれでユーザー用の systemd が起動しました)。

よくある質問

Q. systemctl とは何ですか? A. systemd(Linux の起動とサービスを管理する仕組み)に指示を出すコマンドです。サービスの起動・停止・再起動・自動起動の設定・状態の確認を行います。systemd 本体ではなく、打ったときだけ動く窓口です。

Q. systemd とは何ですか? A. Linux で最初に起動するプロセス(PID 1)として動き、サービス・マウント・タイマーなどを「ユニット」として管理するソフトウェアです。以前の SysVinit に代わり、主なディストリビューションの標準になっています。

Q. restart と reload の違いは? A. restart はプロセスを止めて新しく起動し、reload はプロセスを止めずに設定だけ読み直させます。今回の測定では、restart 中は問い合わせが5回失敗し、reload 中は0回でした。reload は ExecReload= があるサービスだけで使えます。

Q. enable したのに起動していません。 A. enable は「次の OS 起動から自動で動かす」設定で、今すぐは起動しません。systemctl enable --now 名前 にすると、今すぐの起動も同時に行います。

Q. daemon-reload はいつ必要ですか? A. unit ファイルやドロップインをエディターで直接作った・書き換えたときです。systemctl edit で保存した場合は自動で行われます。daemon-reload だけでは動いているプロセスは変わらないので、続けて restart します。

Q. status で failed と出ました。まず何を見ればよいですか? A. Process 行の status=番号/名前 です。203/EXEC・217/USER のように200番台なら unit ファイルの設定(実行ファイル・ユーザー)、1/FAILURE などならプログラム自身のエラーなので journalctl -u 名前 でアプリの出力を読みます。

Q. Start request repeated too quickly と出て起動できません。 A. 既定の上限(10秒間に5回)を超えて起動したため、systemd が起動を止めています。落ちる原因を直してから systemctl reset-failed 名前 を実行すると、また起動できます。

Q. Docker のコンテナの中で systemctl が使えません。 A. コンテナの PID 1 は systemd ではないため、System has not been booted with systemd as init system (PID 1). Can't operate. と出ます。コンテナでは ENTRYPOINT・CMD でプログラムを直接起動し、再起動はコンテナの再起動の設定に任せるのが基本です。

Q. WSL で systemctl を使うには? A. Microsoft Learn によると、WSL 0.67.6 以降で使えます。wsl --install で入れた Ubuntu は既定で有効です。ほかのディストリビューションでは /etc/wsl.conf に [boot] と systemd=true を書き、PowerShell で wsl.exe --shutdown を実行してから開き直します。systemctl status で状態が表示されれば有効です。

まとめ

  • systemd は PID 1 として動くサービスの管理役で、systemctl はそこへ指示を出すコマンド。PID 1 が systemd でないコンテナでは使えない。
  • まず systemctl status の Loaded・Active・Process 行と末尾のログを読む。ログの続きは journalctl -u 名前。
  • restart は止めて起動し直し(今回の測定で問い合わせ5回失敗)、reload は止めずに読み直す(0回)。enable は次の起動からで、今すぐなら --now。
  • 自作の unit は /etc/systemd/system に置き、systemd-analyze verify → daemon-reload → start → enable の順。Type=simple は起動失敗でも start が成功を返すので、Type=exec も検討する。
  • failed は status=番号で切り分け、直したら reset-failed。timer は .service と .timer の組で作り、既定で最大1分ずれる点に気を付ける。

参考・出典

いずれも確認日は 2026年10月29日です。

  • systemd 公式マニュアル「systemctl」:https://www.freedesktop.org/software/systemd/man/latest/systemctl.html
  • systemd 公式マニュアル「systemd.service」:https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
  • systemd 公式マニュアル「systemd.timer」:https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html
  • systemd 公式マニュアル「systemd.exec」:https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html
  • Microsoft Learn「Use systemd to manage Linux services with WSL」:https://learn.microsoft.com/ja-jp/windows/wsl/systemd
  • Red Hat「第10章 systemd によるサービス管理」(RHEL 7 システム管理者のガイド):https://docs.redhat.com/ja/documentation/Red_Hat_Enterprise_Linux/7/html/system_administrators_guide/chap-managing_services_with_systemd

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「systemctlコマンドの使い方とsystemdとは|statusとエラー原文」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ
参加受付中

AI駆動開発、 無料セミナー