systemdサービスが起動しない・failedになる時の調査手順|依存関係とユニット設定の直し方

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Linuxトラブルシューティング > systemdサービスが起動しない・failedになる時の調査手順|依存関係とユニット設定の直し方
「systemctl start を実行したのに、すぐに stopped になってしまう」「status コマンドで確認したら failed と表示されているが、どこを直せばいいのか分からない」
サーバー管理の現場で、こうした状況は珍しくない。特に自作のユニットファイルを書いた直後や、OS を RHEL 8 系から RHEL 9 系へ移行した際によく発生する。

systemd サービスの起動失敗は、正しい手順でログを追えば、ほとんどのケースで原因を特定できる。闇雲に設定を変更するのではなく、「なぜ failed になっているのか」を確認する順序が重要だ。
本記事では、systemd サービスが起動しない・failed になる時の調査手順を、journalctl のログ確認・依存関係のチェック・ユニットファイルの設定修正まで、現場で即使える手順で解説する。

動作確認環境:RHEL 9.4 / Ubuntu 24.04 LTS で確認済み。

この記事のポイント

・systemctl status → journalctl -xe の順で調査すれば原因の9割が特定できる
・failed の多くは ExecStart のパス誤り・実行権限・依存サービスの未起動が原因
・ユニットファイルを編集したら必ず daemon-reload を実行してから再起動する
・依存関係エラーは After/Requires の見直しか、依存先サービスの修正で解消できる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

systemdサービスがfailedになる主な原因

systemctl status で failed と表示されるケースは、大きく次のカテゴリに分類できる。

ExecStart の設定ミス:実行ファイルのパスが間違っている、または実行権限(+x)がない
依存関係の問題:起動順序(After/Requires)が正しく設定されていない
Type 指定のミス:フォアグラウンドで動くのに Type=forking を指定しているなど
環境変数・設定ファイルの欠落:必要なファイルやディレクトリが存在しない
タイムアウト:起動に時間がかかりすぎて TimeoutStartSec を超過している

どのカテゴリに該当するか、以下の手順で絞り込んでいく。

基本調査手順:ログから原因を特定する

1. systemctl statusでエラーの種類を把握する

まず systemctl status コマンドで、サービスの状態と直近のログを確認する。-l オプションを付けると、長いエラーメッセージが途中で省略されなくなる。

# サービス状態の確認(-l で長いメッセージも省略しない) $ systemctl status myapp.service -l

実際の出力例(RHEL 9.4、server01 での確認):

* myapp.service - My Application Service Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: disabled) Active: failed (Result: exit-code) since Fri 2026-07-11 09:23:14 JST; 3min ago Process: 12847 ExecStart=/usr/local/bin/myapp --config /etc/myapp/app.conf (code=exited, status=203/EXEC) Main PID: 12847 (code=exited, status=203/EXEC) CPU: 2ms Jul 11 09:23:14 server01 systemd[1]: myapp.service: Control process exited, code=exited, status=203/EXEC Jul 11 09:23:14 server01 systemd[1]: myapp.service: Failed with result 'exit-code'. Jul 11 09:23:14 server01 systemd[1]: Failed to start My Application Service.

Active: failed (Result: exit-code) は「プロセスが非ゼロの終了コードを返した」ことを意味する。
status=203/EXEC は特に重要で、「ExecStart に指定した実行ファイルが見つからない、または実行できない」を意味している。この時点でパスか権限の問題に目星がつく。

よく見かける Result の値とその意味をまとめると次の通りだ。

exit-code:プロセスが 0 以外の終了コードで終了(設定ミスや起動失敗)
signal:プロセスがシグナルで強制終了(segfault など)
timeout:TimeoutStartSec を超えて応答がなかった
resources:メモリ・ファイルディスクリプタ等の上限超過

2. journalctlで詳細ログを確認する

systemctl status の出力だけでは情報が不十分な場合、journalctl でより詳細なログを確認する。

# 直近のシステムジャーナルを確認(エラー前後のコンテキストが見やすい) $ journalctl -xe # 特定サービスのログのみ抽出(直近50行) $ journalctl -u myapp.service -n 50 # 直近の起動失敗のみ表示(リアルタイム追跡) $ journalctl -u myapp.service -f # 優先度 error 以上のみ表示 $ journalctl -u myapp.service -p err

journalctl -xe の出力例(server01 での確認):

Jul 11 09:23:14 server01 systemd[1]: Starting My Application Service... Jul 11 09:23:14 server01 systemd[1]: myapp.service: Control process exited, code=exited, status=203/EXEC Jul 11 09:23:14 server01 systemd[1]: myapp.service: Failed with result 'exit-code'. Jul 11 09:23:14 server01 systemd[1]: Failed to start My Application Service. -- Subject: Unit myapp.service has failed -- Defined-By: systemd -- Support: https://access.redhat.com/support -- Unit myapp.service has entered the 'failed' state with result 'exit-code'.

status=203/EXEC が確認できたので、次に実行ファイルの存在と権限を確認する。

3. systemctl catでユニットファイルを確認する

journalctl のログで原因のカテゴリを絞り込んだら、ユニットファイルの設定を確認する。

# ユニットファイルの内容を確認(読み込まれているすべての設定を表示) $ systemctl cat myapp.service # ユニットファイルを直接編集 $ systemctl edit --full myapp.service # 設定値の有効状態を確認(dropinも含めた最終的な設定値) $ systemctl show myapp.service

systemctl cat の出力例:

# /etc/systemd/system/myapp.service [Unit] Description=My Application Service After=network.target [Service] Type=simple ExecStart=/usr/local/bin/myapp --config /etc/myapp/app.conf Restart=on-failure [Install] WantedBy=multi-user.target

ExecStart のパスを確認したところ、/usr/local/bin/myapp が存在しないことが判明した。

確認コマンド:

# 実行ファイルの存在と権限を確認 $ ls -la /usr/local/bin/myapp ls: cannot access '/usr/local/bin/myapp': No such file or directory # インストール先を探す(which コマンドまたは find) $ which myapp 2>/dev/null || find /usr /opt -name "myapp" -type f 2>/dev/null /opt/myapp/bin/myapp

実行ファイルが /opt/myapp/bin/myapp に存在することが分かった。ユニットファイルの ExecStart を修正する。

依存関係エラーを解消する

1. After/Requires/Wantsの違いを理解する

「Dependency failed for XXX.service」というエラーは依存関係の問題だ。systemd の依存関係ディレクティブの違いを理解することが解消への近道になる。

After=:起動順序のみ制御。依存先が失敗しても自サービスは起動を試みる
Requires=:強い依存。依存先が起動していないと自サービスも起動しない
Wants=:弱い依存。依存先が失敗しても自サービスは起動を続ける
BindsTo=:Requires よりさらに強い。依存先が停止したら自サービスも停止する

よくある間違いは、Requires= に指定したサービスが failed になっているケースだ。
例えば Requires=postgresql.service と書いていて、PostgreSQL が起動に失敗していれば、自サービスも起動できない。

2. 依存先サービスの状態を確認する

# 依存先サービスの状態確認 $ systemctl status postgresql.service # 失敗しているサービスを一括確認 $ systemctl list-units --state=failed # 全サービスの起動状態を確認 $ systemctl list-units --type=service --state=active

依存先サービスが failed の場合、まず依存先を修正してから自サービスを再起動する順序が重要だ。

3. systemd-analyzeで依存ツリーを確認する

依存関係が複雑になってきたら、systemd-analyze コマンドで視覚的に確認できる。
詳細な使い方は「systemd-analyze で起動時間計測」も参照してほしい。

# 特定サービスの依存ツリーを表示 $ systemd-analyze critical-chain myapp.service # ユニットファイルの文法チェック $ systemd-analyze verify myapp.service # 起動シーケンス全体のタイムライン確認 $ systemd-analyze plot > /tmp/boot-timeline.svg

systemd-analyze verify は設定ミスの早期発見に非常に有効だ。ExecStart のパス不正、Type の矛盾など、起動前に文法エラーを検出できる。

systemd のトラブルシューティングをもっと体系的に学びたい方へ

Linux Master Pro Seminar では、systemd によるサービス管理・依存関係の設計・障害時の切り分け手順を、RHEL 9 実機を使ったハンズオンで習得できます。

セミナー詳細を確認する >>

ユニットファイルの設定ミスを修正する

1. ExecStartのパス・実行権限を確認する

status=203/EXEC や status=217/USER などのエラーは、ExecStart 周辺の設定ミスを示している。

status=203/EXEC:実行ファイルが存在しない、または実行権限がない
status=217/USER:User= に指定したユーザーが存在しない
status=200/CHDIR:WorkingDirectory= に指定したディレクトリが存在しない

# 実行ファイルの確認 $ ls -la /opt/myapp/bin/myapp -rwxr-xr-x 1 root root 2048576 Jul 10 14:30 /opt/myapp/bin/myapp # 実行権限がない場合は付与する $ chmod +x /opt/myapp/bin/myapp # User= に指定するユーザーの存在確認 $ id myappuser uid=1001(myappuser) gid=1001(myappuser) groups=1001(myappuser)

2. Typeの指定ミスを修正する(forking vs simple)

Type の指定ミスは見落としやすいが、起動失敗の定番原因のひとつだ。

Type=simple(デフォルト):ExecStart のプロセスがフォアグラウンドで動き続けるサービス向け。プロセスが即座に終了するとfailed になる
Type=forking:デーモン型(二重フォークして親プロセスが終了するサービス)向け。PIDFile= の指定が必要
Type=oneshot:実行して終了するジョブ向け。終了しても failed にならない
Type=notify:プロセスが準備完了を systemd に通知するまで待つ(Nginx 等が対応)

旧来の init スクリプト(SysV init)から移植したサービスで Type=forking を指定しているのに PIDFile= が設定されていないケースをよく見かける。

# Type=forking を使う場合の正しい書き方 [Service] Type=forking PIDFile=/var/run/myapp.pid ExecStart=/opt/myapp/bin/myapp -D --pidfile /var/run/myapp.pid

3. daemon-reloadとrestartを実行する

ユニットファイルを編集した後は、必ず daemon-reload を実行してから再起動する。この手順を忘れると、変更前の設定のままサービスが起動してしまう。

# ユニットファイルを編集 $ vi /etc/systemd/system/myapp.service # 編集後: daemon-reload で設定を再読み込み(必須) $ systemctl daemon-reload # サービスの再起動 $ systemctl restart myapp.service # 起動を確認 $ systemctl status myapp.service

daemon-reload を忘れた場合、古いユニットファイルの設定が残ったまま起動を試みるため、修正したのに同じエラーが繰り返される。daemon-reload は編集のたびに実行する習慣をつけておこう。
また、起動時に自動起動させたい場合は enable も設定する。

# 自動起動を有効化(OS 再起動後も起動) $ systemctl enable myapp.service # 自動起動の有効化と即時起動を同時に行う $ systemctl enable --now myapp.service # 自動起動状態の確認 $ systemctl is-enabled myapp.service enabled

よくあるエラーパターンと対処法

「Failed to start」とExecStart系エラー

ポートがすでに使用中の場合も起動に失敗する。サービスが使用するポートを別プロセスが占有していないか確認しよう。
ポート確認の詳細は「Linux ポート確認の全コマンド」が参考になる。

# 特定ポートの使用状況を確認(例: 8080番) $ ss -tlnp | grep 8080 LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("oldapp",pid=9923,fd=5)) # 占有しているプロセスを終了 $ kill 9923 # または systemd サービスの場合は stop $ systemctl stop oldapp.service

「Dependency failed」の解消方法

# 依存関係エラーのログ確認 $ journalctl -u myapp.service | grep -i "dependency\|depend\|failed" Jul 11 09:35:22 server01 systemd[1]: Dependency failed for My Application Service. Jul 11 09:35:22 server01 systemd[1]: myapp.service: Job myapp.service/start failed with result 'dependency'. # 依存先の状態確認 $ systemctl status postgresql.service * postgresql.service - PostgreSQL Database Server Active: failed (Result: exit-code) since Fri 2026-07-11 09:34:50 JST # 依存先を先に修正・起動してから自サービスを起動 $ systemctl start postgresql.service $ systemctl start myapp.service

依存関係が不要であれば、ユニットファイルの Requires= を Wants= に変更することで、依存先の失敗を無視できるようになる。ただし、本当に依存関係が必要かどうかを先に検討すること。

timeoutによるfailed

起動に時間がかかるサービス(初期化処理が重い Java アプリ等)では、TimeoutStartSec のデフォルト値(90秒)を超過して failed になることがある。

# ログでタイムアウトを確認 $ journalctl -u myapp.service | grep -i timeout Jul 11 10:12:05 server01 systemd[1]: myapp.service: Start operation timed out. Terminating. # ユニットファイルにタイムアウト値を追加 [Service] TimeoutStartSec=300 # または無制限に設定(推奨しないが必要に応じて) TimeoutStartSec=infinity

httpd(Apache)サービスの管理については「httpd の基本操作」も参考にしてほしい。

本記事のまとめ

systemd サービスの起動失敗を調査する際の手順と、よく使うコマンドをまとめる。
やりたいこと コマンド
サービスの状態・直近ログを確認 systemctl status サービス名 -l
詳細ログを確認(直近50行) journalctl -u サービス名 -n 50
エラー以上のログのみ表示 journalctl -u サービス名 -p err
ユニットファイルの内容確認 systemctl cat サービス名
ユニットファイルの文法チェック systemd-analyze verify サービス名.service
依存ツリーの確認 systemd-analyze critical-chain サービス名.service
失敗中サービスを一覧表示 systemctl list-units --state=failed
設定変更後の再読み込み systemctl daemon-reload
サービス再起動 systemctl restart サービス名
自動起動有効化と即時起動 systemctl enable --now サービス名
systemd のサービス管理を体系的に理解すると、障害対応のスピードが大幅に上がる。
起動時間の詳細分析には「systemd-analyze で起動時間計測」も参照してほしい。
また、mount の依存関係が絡む場合は「mount コマンドの使い方」が役立つ。

今回解説した調査手順を身につけることで、failed ステータスで手が止まる状況から脱却できるはずだ。

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、

Linux Master Pro Seminar では、systemd によるサービス管理・障害切り分け・サーバー構築を、RHEL 10 実機を使った2日間ハンズオンで実践的に習得できます。3,100名以上の受講実績。

セミナー詳細・日程を確認する >>

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。