こんにちは、インフラエンジニアのryuです。
設定ファイルを直して、サービスを再起動して、それでも症状が変わらない。そんな時間を過ごしたことはないでしょうか。
私は何度もあります。しかも厄介なことに、こういうときの再起動コマンドは、だいたい成功します。エラーも出ません。プロンプトが何事もなく返ってきて、それなのに挙動は前のまま。
原因を後から調べると、単純なことが多いんです。systemdが読んでいたのは、自分が編集したファイルではなかった。あるいは、編集はされていたけれど、systemdはまだ読み直していなかった。
今日は、Linuxのサービスが起動しない・設定が反映されないときに、systemdが何を見て動いているのかを追いかける話をします。個別のコマンドの使い方というより、どの順番で何を確認すれば犯人にたどり着けるかという話です。
systemdは、どのファイルを読んでいるのか¶
最初に押さえておきたいのが、ユニットファイルの置き場所が1か所ではないという事実です。
nginx.serviceのようなユニットは、複数のディレクトリを決まった優先順位で探索して見つかります。システム用の主なものを、優先度が高い順に並べるとこうなります。
| ディレクトリ | 主な用途 | 優先度 |
|---|---|---|
/etc/systemd/system/ |
管理者が自分で置く・上書きする場所 | 高 |
/run/systemd/system/ |
実行時に生成される一時的な定義 | 中 |
/usr/local/lib/systemd/system/ |
ローカルにインストールしたもの | 低 |
/usr/lib/systemd/system/ |
パッケージが配置する本来の定義 | 最も低い |
systemdのマニュアルには、先に並んでいるディレクトリで見つかったユニットファイルが、後ろのディレクトリにある同名のファイルを上書きすると書かれています。
つまり、/etc/systemd/system/nginx.serviceがあれば、パッケージが置いた/usr/lib/systemd/system/nginx.serviceは完全に無視されます。前任者が緊急対応で/etcにコピーを置いたまま忘れている、というのはよくある話です。
この構造がやっかいなのは、パッケージを更新しても症状が変わらない点にあります。更新で書き換わるのは/usr/lib側だけなので、/etcにコピーが残っているかぎり、古い定義がそのまま生き続けます。「バージョンを上げたのに直らない」と言われたら、まずここを疑ってください。
実際に読まれている中身は systemctl cat で見る¶
では、いま有効な定義はどれなのか。推測するより、systemdに聞いたほうが早いです。
# そのユニットの本体(fragment)と、適用されている追加設定(drop-in)を全部表示する
systemctl cat nginx.service
# 出力の先頭に、読んでいるファイルのパスがコメントで出る
# /usr/lib/systemd/system/nginx.service
# ...
# /etc/systemd/system/nginx.service.d/override.conf
systemctl catは、そのユニットの本体ファイルと、適用されているドロップインファイルの中身をまとめて出してくれます。ファイルパスがコメント行として付くので、「自分が編集したのはどれだったか」が一目で分かります。
ここで言うドロップインは、<ユニット名>.d/というディレクトリに置く追加の設定ファイルです。本体を丸ごと書き換えるのではなく、変えたい項目だけを上書きできます。マニュアルにも、/etc/のドロップインが/run/より、/run/が/usr/lib/より優先されること、そして同じ階層に複数あるときはファイル名の辞書順に適用されることが書かれています。
ドロップインは手で作らず、次のコマンドで作るのが安全です。
# /etc/systemd/system/nginx.service.d/override.conf を作って編集する
sudo systemctl edit nginx.service
# 本体をまるごとコピーして上書きしたい場合(基本は非推奨)
sudo systemctl edit --full nginx.service
systemctl editは一時ファイルを編集させて、エディタが正常終了したときだけ本来の場所へ書き込みます。編集途中で中断しても、壊れた設定が残りません。
編集したら daemon-reload を忘れない¶
ここが、冒頭の「再起動したのに変わらない」の最大の犯人です。
systemdは、ユニットファイルを毎回ディスクから読み直すわけではありません。起動時に読み込んだ内容をメモリ上に持っていて、systemctl restartはそのメモリ上の定義でプロセスを起動し直します。ファイルを書き換えただけでは、その内容は届いていません。
# ユニットファイルやdrop-inを編集したあとは必ず実行する
sudo systemctl daemon-reload
sudo systemctl restart nginx.service
daemon-reloadは、マニュアルの言葉を借りると「systemdマネージャの設定を再読み込みし、すべてのジェネレータを再実行し、すべてのユニットファイルを読み直し、依存関係ツリー全体を作り直す」動作です。
親切なことに、これを忘れているとsystemctl statusが教えてくれます。
Warning: The unit file, source configuration file or drop-ins of nginx.service changed on disk. Run 'systemctl daemon-reload' to reload units.
この行が出ているのに見落として30分溶かす、というのを私は何度もやりました。statusを見るときは、まずこの警告が出ていないかを確認してください。
なお、似た名前のsystemctl reloadはまったく別物です。あちらはサービス自身に設定を読み直させる操作で、Apacheならhttpd.confの再読み込みにあたります。systemd側の定義を読み直すのがdaemon-reload、サービス側の設定を読み直すのがreload。ここは混同しやすいところです。Apacheの起動・停止・再起動そのものについてはApacheの再起動の方法は?にまとまっています。
起動しないときに systemctl status のどこを見るか¶
daemon-reloadの問題でなければ、次は起動そのものを追います。
systemctl statusは、ユニットの状態と、直近のジャーナル(ログ)の抜粋をまとめて出してくれます。人間が読むためのコマンドで、機械的に処理したいときはsystemctl showのほうを使います。
見るべき行は、だいたい決まっています。
| 行 | 見るポイント |
|---|---|
Loaded: |
読んでいるファイルのパス。enabledかdisabledか。maskedなら起動できない |
Active: |
いまの状態。failed/activating/inactiveで意味がまったく違う |
Main PID: |
終了している場合、終了コードと終了理由(status=1、signal=SEGVなど) |
Process: |
ExecStartPreなど前処理で落ちていないか |
| 末尾のログ | ジャーナルの最後の数行。ここに本当の理由が出ていることが多い |
Active: の状態語を読み分ける¶
Active:に出る言葉は、そのまま切り分けの分岐になります。
failedなら、起動を試みて失敗しています。終了コードを見て、アプリケーション側のログへ進みます。
activatingのまま止まっているなら、起動は始まっているのに完了と判定されていません。これは後で触れるType=の食い違いでよく起きます。
inactive (dead)なら、そもそも起動を試みていません。enableし忘れか、依存するユニットが先に失敗している可能性を疑います。
Loaded:がmaskedになっていたら、そのユニットは/dev/nullへリンクされていて、startしても起動しません。過去に誰かが意図的に封じた形跡です。
ジャーナルは -u と -b で絞る¶
statusの末尾に出るログは数行だけなので、詳しく見たいときはjournalctlに移ります。
# このユニットの、今回の起動以降のログを、ページャなしで全部出す
journalctl -u nginx.service -b --no-pager
# 直近50行だけ見る/出たそばから追いかける
journalctl -u nginx.service -n 50
journalctl -u nginx.service -f
# 時間で絞る/重要度で絞る(err以上)
journalctl -u nginx.service --since "2026-09-12 01:00" --until "2026-09-12 02:00"
journalctl -u nginx.service -p err
# メッセージカタログの解説を付ける
journalctl -u nginx.service -xe
-uは対象のユニット、-bは今回のブート以降という意味です。journalctlは既定で古い順に表示するので、長いログでは-eで末尾へ飛ぶか、-nで行数を絞ると読みやすくなります。
ひとつ注意点があります。ジャーナルの保存先は/var/log/journal/と/run/log/journal/の2種類で、後者は再起動で消える一時領域です。/var/log/journal/が存在しない環境では、再起動前のログは残りません。「昨夜の障害のログを見ようとしたら空だった」という事故は、ここが原因のことがあります。
テキストのログファイルを追いかける側のコマンドについてはLinuxでログ監視するコマンドtailとlessの使い方解説、出力先の設定については【Linux】syslogの設定方法とは?が参考になります。
つまずきやすい3つのパターン¶
ここからは、実際に見かける頻度が高い詰まり方を3つ挙げます。
enableしたのに起動していない(あるいはその逆)¶
systemctl enableとsystemctl startは、別の操作です。マニュアルにも、この2つは直交している(どちらか一方だけの状態がありうる)と明記されています。
enableは、自動起動の仕組みにユニットを引っかける操作です。startは、いまプロセスを起動する操作です。
# いま起動する(再起動したら上がってこない)
sudo systemctl start nginx.service
# 次回以降の自動起動を有効にする(いまは起動しない)
sudo systemctl enable nginx.service
# 両方まとめて
sudo systemctl enable --now nginx.service
検証環境でstartだけして動作確認を終え、サーバーを再起動した翌朝に上がってこない。この事故の正体は、たいていこれです。逆にenableだけして「起動したはず」と思い込むパターンもあります。
確認はsystemctl is-enabled nginx.serviceとsystemctl is-active nginx.serviceで、それぞれ別に行ってください。
再起動を繰り返して、最後に止まる¶
Restart=を設定していると、プロセスが落ちたときにsystemdが自動で起動し直します。指定できる値はno、on-success、on-failure、on-abnormal、on-watchdog、on-abort、alwaysで、既定値はnoです。再起動までの待ち時間RestartSec=の既定値は100ミリ秒です。
ここで問題になるのが、起動レート制限です。
ユニットがStartLimitIntervalSec=で指定した時間内にStartLimitBurst=で指定した回数を超えて起動されると、それ以上の起動が許可されなくなります。既定値はマネージャ設定のDefaultStartLimitIntervalSec=(10秒)とDefaultStartLimitBurst=(5回)です。
設定ミスで即座に落ちるサービスにRestart=alwaysが付いていると、100ミリ秒間隔で5回失敗し、10秒以内に上限へ到達します。その結果、ログには「start request repeated too quickly」という趣旨のメッセージが残り、サービスは止まります。
# レート制限のカウンタを手動で流す
sudo systemctl reset-failed nginx.service
sudo systemctl start nginx.service
reset-failedは再起動レートのカウンタをリセットするコマンドで、管理者が手で起動したいのに制限が邪魔をする場合に使うものだとマニュアルに説明があります。
ただし、これは症状を消すだけです。落ちている原因そのものは、先ほどのジャーナルで追ってください。
ここで一点、設計の話をしておきます。Restart=alwaysは便利ですが、万能ではありません。設定ミスのように何度やり直しても直らない失敗に対しては、再起動を繰り返すだけで復旧しませんし、そのあいだログが同じ内容で埋まって、本当の原因が読みにくくなります。外部要因で一時的に落ちるサービスには効きますが、起動時の設定読み込みで死ぬサービスには向かない、と覚えておくと判断が早くなります。RestartSec=を数秒に伸ばしておくと、ログが読める速度に落ち着きます。
Type=の指定と、プロセスの実際の振る舞いが合っていない¶
activatingのまま進まない、あるいは起動したのにsystemdが失敗と判断する。この手の症状は、Type=の食い違いを疑います。
指定できる値はsimple、exec、forking、oneshot、dbus、notify、notify-reload、idleです。ExecStart=があってType=を書いていない場合はsimpleとして扱われます。
よくあるのは、デーモンが自分で子プロセスを作って親が終了する(デーモン化する)タイプなのにType=simpleになっているケースです。systemdから見ると親プロセスが終了したので、サービスが終わったように見えます。この場合はType=forkingとPIDFile=を指定します。
逆に、フォアグラウンドで動き続けるプロセスにType=forkingを付けると、systemdは子プロセスの出現を待ち続けてactivatingから進みません。
プロセスの親子関係を実際に確認したいときは、psの出力を見るのが早道です。【Linux】プロセスを確認するpsコマンドの使い方解説にオプションがまとまっているので、ps -efでPPIDを追ってみてください。
切り分けの順番を決めておく¶
ここまでの内容を、上から順に試せる形に並べておきます。夜中に呼び出されたときは、この順番どおりに手を動かせば十分です。
| 順番 | やること | 見つかるもの |
|---|---|---|
| 1 | systemctl status <unit> |
daemon-reload警告、Active状態、終了コード |
| 2 | systemctl cat <unit> |
実際に読まれているファイルとdrop-in |
| 3 | sudo systemctl daemon-reload |
編集が反映されていなかったケース |
| 4 | journalctl -u <unit> -b --no-pager |
起動失敗の本当の理由 |
| 5 | systemctl is-enabled / is-active |
enableとstartの取り違え |
| 6 | systemd-analyze verify <unit> |
ユニットファイルの記述ミス |
| 7 | systemctl reset-failed |
レート制限で止まっていたケース |
1から4までで、体感8割は決着します。逆に、ここまでで原因が見えないときは、サービス単体ではなく依存関係や外部要因を疑う段階です。ポートの衝突、ディスクの枯渇、名前解決の失敗などが候補になります。
表の6行目にあるsystemd-analyze verifyは、地味ですが押さえておきたいコマンドです。ユニットファイルを実際に起動せずに読み込んで、綴りの誤りや存在しない指定を指摘してくれます。本番に反映する前に一度通しておくと、深夜に気づく種類のミスを昼のうちに潰せます。
ディスクまわりはディスクが100%なのに、duで数えると空いている。Linuxの容量トラブルを切り分ける順番、通信が絡む場合はその通信、どこで止まっていますか? ping・ss・tcpdumpで疎通トラブルを層ごとに切り分けるに、それぞれの追い方をまとめています。
なお、こうした切り分けの順番をチームで共有しておくと、夜間の当番を新しいメンバーへ引き継ぐときにそのまま教材になります。当番の広げ方については夜中の呼び出し当番、新人インフラエンジニアはいつから入れる?で書きました。
InfraAcademyでは、こうしたLinuxの運用操作を実機で試しながら学べるカリキュラムを用意しています。systemdまわりを断片的な知識ではなく体系として学び直したい方は、Linuxロードマップを覗いてみてください。基礎のコマンド操作から入り直したい場合はLinuxコマンドの基本が入口になります。
まとめ¶
サービスが起動しない、設定が反映されないときの追い方を整理してきました。
いちばん多い原因は、systemdがまだ読み直していないことです。ユニットファイルやドロップインを編集したらdaemon-reload。これだけで相当数が片付きます。
次に見るのは、そもそもどのファイルが読まれているかです。/etcが/usr/libを上書きする構造を知っていれば、systemctl catの出力がそのまま答えになります。
そして、Active:の状態語を読み分けること。failedとactivatingとinactiveでは、次に進む方向がまったく違います。
最後に、enableとstartは別の操作であること。これを取り違えると、再起動した翌朝にサービスが上がってきません。
systemdは寡黙に見えて、実はかなり饒舌です。statusの警告行も、ジャーナルの1行も、こちらが読みさえすればちゃんと理由を語っています。読み方さえ決めておけば、深夜の30分は5分になります。
参考記事¶
- systemd.unit(5) マニュアル(ユニットの探索順、ドロップインの優先順位、StartLimit)
- systemctl(1) マニュアル(daemon-reload、cat、edit、enableとstartの違い)
- systemd.service(5) マニュアル(Restart=の値、RestartSec=の既定値、Type=)
- journalctl(1) マニュアル(-u、-b、-x、保存先の違い)
- systemd-system.conf(5) マニュアル(DefaultStartLimitIntervalSec=とDefaultStartLimitBurst=の既定値)



