systemdサービス管理完全ガイド【2026年版】

※本記事にはプロモーションを含む場合があります。
- 2026年時点でUbuntu 24.04 LTSやRHEL 10などほぼ全ての主要ディストリビューションがsystemdを標準採用
- 並列起動によりSysVinit比で起動時間が約40%短縮されたとする社内ベンチマークがある
- ユニットファイルは[Unit]/[Service]/[Install]の3セクション構成が基本
- journalctlとsystemctl statusを組み合わせれば障害切り分けの大半はカバーできる
- ProtectSystemやNoNewPrivilegesなど7種類前後のディレクティブでセキュリティを底上げできる
systemdとは何か
systemdは、Linuxカーネル起動後の初期化プロセス(PID 1)を担うシステム・サービスマネージャーです。2026年現在、Ubuntu 24.04 LTS、RHEL 10、Debian 13、AlmaLinux 10、Fedora Server 42といった主要ディストリビューションで標準採用されており、SysVinitベースの環境を見かける機会はほぼなくなったといわれています。従来のSysVinitはサービスを1つずつ直列で起動していたため、依存するサービス同士が多い構成ほど起動完了までの待ち時間が伸びる傾向にありました。
systemdでは依存関係が解決できるサービス同士を並列で起動できるため、起動時間の短縮効果が見込めます。Red Hat社内ベンチマークでは、RHEL 9環境においてSysVinit時代と比較して起動時間が約40%短縮されたと報告されています。あわせてudevと連携したデバイスの自動検出、journaldによるログの一元管理、cgroupsを用いたリソース制御など、単なる起動処理にとどまらない運用機能が組み込まれている点も特徴です。
- サービス管理:起動・停止・再起動を一元化されたコマンド体系で操作
- デバイス管理:udevと連携し新規デバイスを自動検出
- ログ管理:journaldがバイナリ形式でログを統合保存
- 依存関係解決:Requires/Afterなどのディレクティブで自動制御
- リソース制御:cgroupsによりCPU・メモリ使用量を制限
従来方式との違いを整理すると、次のようになります。
| 比較項目 | SysVinit | systemd |
|---|---|---|
| 起動方式 | 直列起動 | 並列起動(依存関係に基づく) |
| 依存関係解決 | スクリプト側で個別対応 | Requires/After等で自動解決 |
| リソース制御 | 基本的になし | cgroupsでCPU・メモリ制限が可能 |
| ログ管理 | syslog(テキスト形式) | journald(バイナリ形式・メタデータ付き) |
| 異常終了時の復旧 | 手動対応が前提 | Restart=で自動再起動が可能 |
Restart=on-failureを設定しておくと、サービスがクラッシュした際に自動再起動を試みるため、深夜のアラート対応回数を減らせる現場もあるようです。運用チームの負荷軽減という観点では、こうした自動化機能がsystemd移行の後押しになっているケースが少なくありません。
基本構成を知る
systemdサービスの実体は、/etc/systemd/system/配下に置く拡張子.serviceのユニットファイルです。ディストリビューション標準のサービスは/usr/lib/systemd/system/にありますが、カスタム設定や独自サービスは/etc/systemd/system/側に配置し、上書き優先されるという仕組みを理解しておくと管理がしやすくなります。
| セクション | 主なディレクティブ | 説明 |
|---|---|---|
| [Unit] | Description, After, Requires, Wants | サービスの説明や依存関係を定義 |
| [Service] | Type, ExecStart, ExecStop, Restart, User, Group | 実行方法や動作モードを指定 |
| [Install] | WantedBy | 自動起動の対象ターゲットを指定 |
Nginxサービスのユニットファイルを例に見てみます。
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/usr/sbin/nginx -s quit
PrivateTmp=true
User=nginx
Group=nginx
[Install]
WantedBy=multi-user.targetType=forkingはNginxがバックグラウンドで動作する方式であることを示し、User=nginxによりroot権限を使わず専用ユーザーで実行させています。動作モードにはいくつか種類があり、アプリケーションの実装形態に合わせて選ぶ必要があります。
| Type値 | 動作モード | 説明 | 使用例 |
|---|---|---|---|
| simple | 単純なプロセス | フォアグラウンドで動作しそのまま常駐 | Webサーバー(Nginx、Apache) |
| forking | デーモンプロセス | 親プロセスがforkし親は直後に終了 | データベース(MySQL、PostgreSQL) |
| oneshot | 一時的なタスク | 一度実行されると終了するタスク | 初期設定スクリプト |
| dbus | D-Busサービス | D-Bus経由で制御可能なサービス | デスクトップ環境のサービス |
| notify | 通知付きプロセス | 起動完了をsystemdへ通知 | 高可用性サービス |
PythonのWebアプリケーションであれば、次のような設定が一つの型になります。
[Unit]
Description=My Python Web Application
After=network.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=always
RestartSec=5s
[Install]
WantedBy=multi-user.targetリソース制限も同じセクションに書けます。メモリを512Mまで、CPUを50%までに制限したい場合は以下のように指定します。
[Service]
MemoryLimit=512M
MemorySwapMax=1G
CPUQuota=50%コンテナ環境や共有ホスト上で複数サービスを稼働させる場合、こうした制限を入れておかないと1つのサービスの暴走が他サービスの応答遅延に波及することがあるため、早い段階で設定しておくと運用が安定しやすくなります。
独自サービス作成
ここではPythonスクリプトを常駐サービス化する例で、実際の作業手順を追ってみます。専用ユーザーでの実行、ディレクトリ配置、ユニットファイル作成、有効化という4つの工程を踏みます。
- 専用ユーザーとグループを作成する(sudo useradd -r -s /bin/false myscriptuser)
- 実行ディレクトリを作成し所有者を変更する(sudo mkdir -p /opt/myscript、sudo chown myscriptuser:myscriptuser /opt/myscript)
- /etc/systemd/system/myscript.serviceを新規作成する
- systemctl daemon-reloadでsystemdに新しいユニットファイルを認識させる
- systemctl enable myscript.serviceで自動起動を設定する
- systemctl start myscript.serviceでサービスを起動する
- systemctl status myscript.serviceで起動状態とメモリ使用量を確認する
ユニットファイルの中身は次のようになります。
[Unit]
Description=My Custom Python Script
After=network.target
[Service]
Type=simple
User=myscriptuser
Group=myscriptuser
WorkingDirectory=/opt/myscript
ExecStart=/usr/bin/python3 /opt/myscript/myscript.py
Restart=always
RestartSec=10s
StandardOutput=syslog
StandardError=syslog
[Install]
WantedBy=multi-user.targetRestartSec=10sは再起動までの待機時間で、短すぎると異常終了と再起動を繰り返す「クラッシュループ」を招くことがあるようです。デプロイ前に以下の項目を確認しておくと、後からのトラブル対応の手間を減らせます。
- □ 実行ユーザーは専用アカウントになっているか
- □ ExecStartのパスは絶対パスで記述されているか
- □ Restart/RestartSecの値は環境に見合っているか
- □ WorkingDirectoryの権限は適切か
- □ daemon-reloadを実行してからstart/enableしているか
起動・停止・再起動
サービス操作はsystemctlコマンドに集約されています。主な操作は次の通りです。
| コマンド | 説明 | 使用例 |
|---|---|---|
| systemctl start | サービスを起動 | systemctl start nginx |
| systemctl stop | サービスを停止 | systemctl stop nginx |
| systemctl restart | サービスを再起動 | systemctl restart nginx |
| systemctl reload | 停止せず設定を再読込 | systemctl reload nginx |
| systemctl status | 状態を表示 | systemctl status nginx |
| systemctl enable | 自動起動を設定 | systemctl enable nginx |
| systemctl disable | 自動起動を解除 | systemctl disable nginx |
設定ファイルのみを変更した場合はreload、実行バイナリ自体を差し替えた場合はrestart、稼働中のときだけ再起動したい場合はtry-restartを使い分けると、無駄な瞬断を避けやすくなります。正常稼働時のsystemctl statusの出力は次のような形になります。
● nginx.service - The NGINX HTTP and reverse proxy server
Loaded: loaded (/etc/systemd/system/nginx.service; enabled)
Active: active (running) since Mon 2026-08-01 10:00:00 JST; 1h ago
Main PID: 1234 (nginx)
Tasks: 2 (limit: 1137)
Memory: 4.2Menabledかつactive (running)であれば、自動起動設定済みかつ現在稼働中であることが読み取れます。通常のsimple型サービスであれば、起動完了までの所要時間は2〜3秒程度に収まるケースが多いとされています。再起動が異常に繰り返される場合は、StartLimitBurst(デフォルトでは5回程度)に達していないか確認する価値があります。
- 設定ファイルの変更のみ:reloadで反映
- 実行ファイル自体を変更:restartで反映
- サービスがクラッシュ:try-restartで復旧を試行
依存関係とターゲット
複数サービスが絡む構成では、起動順序と依存の強さを明示しておくことがトラブル回避につながります。主なディレクティブは次の通りです。
| ディレクティブ | 説明 | 使用例 |
|---|---|---|
| Requires | 必須の依存関係(失敗すると自身も失敗) | Requires=postgresql.service |
| Wants | 任意の依存関係(失敗しても起動は続行) | Wants=network-online.target |
| After | 起動順序の指定 | After=mysql.service |
| Before | 起動順序の指定(逆順) | Before=apache2.service |
| Conflicts | 同時起動できないサービス | Conflicts=postgresql.service |
Webアプリケーションがデータベースに依存する典型例は次のようになります。
[Unit]
Description=My Web Application
After=postgresql.service
Requires=postgresql.service
[Service]
ExecStart=/usr/bin/python3 /opt/myapp/app.py
Restart=always
[Install]
WantedBy=multi-user.targetターゲットは従来のランレベルに相当する概念で、システム全体の状態を切り替える際に使います。
| ターゲット名 | 説明 | 対応するランレベル |
|---|---|---|
| multi-user.target | マルチユーザーモード(テキストログイン) | runlevel 3 |
| graphical.target | グラフィカルモード(GUIログイン) | runlevel 5 |
| rescue.target | レスキューモード(シングルユーザー) | runlevel 1 |
| emergency.target | 緊急モード(rootシェル) | 該当なし |
| poweroff.target | システムシャットダウン | runlevel 0 |
| reboot.target | システム再起動 | runlevel 6 |
ターゲットの切り替えはsystemctl isolate graphical.targetのように実行します。依存関係のトラブルが疑われるときは、次の順序で切り分けると原因にたどり着きやすくなります。
- systemctl list-dependencies myapp.serviceで依存関係を一覧表示する
- 依存先サービス(例:postgresql.service)のsystemctl statusを確認する
- journalctl -u postgresql.service -bでログを確認する
- 循環依存(A→B→A)が発生していないかユニットファイルを見直す
Requiresを多用しすぎると、副次的なサービスが1つ落ちただけで本体サービスまで停止してしまう連鎖障害が起きやすくなるため、必須依存と任意依存(Wants)の使い分けが運用の安定度を左右します。
ログ解析と対処法
systemdは従来のsyslogに代わる統合ログシステムとしてjournaldを備えています。バイナリ形式での保存によりPIDやUID、GIDといったメタデータも一緒に記録されるため、障害調査の際に検索性が高くなる利点があります。
| コマンド | 説明 | 使用例 |
|---|---|---|
| journalctl | 全てのログを表示 | journalctl |
| journalctl -u | 特定サービスのログを表示 | journalctl -u nginx.service |
| journalctl -f | リアルタイム表示 | journalctl -f |
| journalctl –since | 指定時刻以降のログを表示 | journalctl –since “1 hour ago” |
| journalctl -p | 指定優先度以上のログを表示 | journalctl -p err |
デフォルト設定ではジャーナルの保持期間や容量に上限があり、SystemMaxUse=4Gのような設定で最大容量が制御されているケースが一般的とされています。ログローテーションの設定次第では保存日数が30日程度に収まる環境もあれば、監査要件でより長期保存に変更する運用もあります。
よく遭遇するトラブルとその対処は次の通りです。
| トラブルパターン | 主な原因 | 解決策 |
|---|---|---|
| サービスが起動しない | ユニットファイルの構文エラー | journalctl -u .serviceでエラーを確認し修正 |
| サービスが直後に停止する | Type=simpleでforkingプロセスを起動 | Type=forkingに変更しExecStartを見直す |
| 依存サービスが見つからない | サービス名のスペルミスや未インストール | 正しいサービス名を確認しパッケージを導入 |
| リソース不足で停止 | MemoryLimit/CPUQuotaが厳しすぎる | 制限値を実測に合わせて調整 |
| 再起動が繰り返される | RestartとExitCodeの組み合わせ不整合 | Restart=on-failureに変更しExitCodeを見直す |
エンタープライズ環境では、システム障害による1時間あたりのダウンタイムコストが数十万円規模に達すると試算されることもあるようです。パフォーマンス面ではsystemd-analyzeでの起動時間分析が有効で、systemd-analyze blameを実行すれば各サービスの起動所要時間をミリ秒単位で確認できます。稼働率99.9%を目標とする現場では、こうした計測を定期的に行い、不要なサービスの無効化やリソース制限の見直しを繰り返すことが安定運用の下地になります。
セキュリティ強化設定
root権限でサービスを常時稼働させる構成は、脆弱性が見つかった際の影響範囲が大きくなりやすいという弱点があります。systemdには権限を絞り込むためのディレクティブが複数用意されています。
| 設定項目 | 説明 | 設定例 |
|---|---|---|
| User/Group | root権限ではなく専用ユーザーで実行 | User=appuser |
| PrivateTmp | 独立した/tmpディレクトリを使用 | PrivateTmp=true |
| ProtectSystem | システムディレクトリへの書き込みを禁止 | ProtectSystem=strict |
| ProtectHome | ホームディレクトリへのアクセスを禁止 | ProtectHome=yes |
| NoNewPrivileges | 新しい特権の取得を禁止 | NoNewPrivileges=yes |
| RestrictAddressFamilies | 使用可能なアドレスファミリーを制限 | AF_UNIX AF_INET AF_INET6 |
| CapabilityBoundingSet | 使用可能なLinux Capabilityを制限 | CAP_NET_BIND_SERVICE |
Webサーバー向けに強化した設定は次のようになります。
[Service]
User=www-data
Group=www-data
PrivateTmp=true
ProtectSystem=full
ProtectHome=yes
NoNewPrivileges=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
CapabilityBoundingSet=CAP_NET_BIND_SERVICE権限昇格を狙った攻撃による被害額は、1件あたり数百万円規模に達するケースがあるとされています。こうした設定は導入コストがほぼゼロに近い一方で、攻撃の初期段階での被害範囲を専用ユーザーの権限内に封じ込める効果が期待できるため、優先的に着手する価値があります。
コンテナ環境との組み合わせも広がっています。PodmanなどDocker互換のコンテナエンジンとsystemdを併用すると、コンテナ自体をsystemdサービスとして管理でき、自動再起動やリソース制限、ログの一元管理といった機能をコンテナ側にもそのまま適用できます。ホスト側とコンテナ側でユニットファイルの書式がほぼ共通しているため、学習コストを抑えながら運用を標準化しやすい構成といえます。
よくある質問
Q1. systemctl restartとreloadはどう使い分けますか?
設定ファイルのみの変更であればreloadでサービスを止めずに反映でき、実行バイナリや大きな構成変更を行った場合はrestartで完全に再起動する、という使い分けが基本になります。
Q2. サービスが起動しないときの確認手順は?
まずsystemctl status .serviceで直近のエラー概要を確認し、次にjournalctl -u .serviceで詳細ログを見ます。多くの場合、構文エラーかExecStartのパス間違いが原因の8割前後を占めるといわれています。
Q3. ログはどれくらいの期間保存されますか?
journaldの保存期間はディストリビューションの初期設定に依存し、容量ベースでSystemMaxUse=4G程度、日数ベースで30日前後に設定されているケースが多いとされています。監査要件がある場合は/etc/systemd/journald.confで上限を調整できます。
Q4. 自動起動だけを止めたい場合はどうすればいいですか?
稼働中のサービスを止めずに自動起動だけ解除したい場合は、systemctl disable .serviceを使います。現在起動中のプロセスには影響せず、次回のシステム起動時から適用される点がポイントです。
Q5. セキュリティ強化はどの設定から始めるべきですか?
専用ユーザーでの実行(User/Group)とPrivateTmp、NoNewPrivilegesの3点は導入の手間が小さい割に効果が見込みやすく、最初の着手先として選ばれることが多いようです。その後、ProtectSystemやCapabilityBoundingSetで段階的に絞り込んでいく進め方が現実的です。
Q6. サービスの再起動が無限に繰り返されるのはなぜですか?
Restart=alwaysとRestartSecの値が短すぎる組み合わせで、異常終了と再起動を繰り返す状態に陥っていることがあります。RestartSecを10秒程度に延ばし、Restart=on-failureへ変更したうえで根本原因のExitCodeを確認する対応が効果的とされています。
ユニットファイルの構成、依存関係の設計、セキュリティディレクティブの3点を押さえておくと、既存サービスの棚卸しから新規サービスの設計まで一貫した基準で判断しやすくなります。手元の環境で稼働中のサービス一覧をsystemctl list-unit-files –type=serviceで洗い出し、不要な自動起動が残っていないか確認してみるところから着手する余地がありそうです。
本記事はInfra Academy編集部が各ベンダー公式ドキュメント・エンジニア監修をもとに作成しています。インフラ・クラウド構築は環境により異なります。本番環境への適用前に必ずテストを実施してください。情報の正確性には万全を期していますが、最新情報は各公式ドキュメントをご確認ください。 編集ポリシーはこちら




