※本記事にはプロモーションを含む場合があります。

  • 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・メモリ使用量を制限

従来方式との違いを整理すると、次のようになります。

比較項目SysVinitsystemd
起動方式直列起動並列起動(依存関係に基づく)
依存関係解決スクリプト側で個別対応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.target

Type=forkingはNginxがバックグラウンドで動作する方式であることを示し、User=nginxによりroot権限を使わず専用ユーザーで実行させています。動作モードにはいくつか種類があり、アプリケーションの実装形態に合わせて選ぶ必要があります。

Type値動作モード説明使用例
simple単純なプロセスフォアグラウンドで動作しそのまま常駐Webサーバー(Nginx、Apache)
forkingデーモンプロセス親プロセスがforkし親は直後に終了データベース(MySQL、PostgreSQL)
oneshot一時的なタスク一度実行されると終了するタスク初期設定スクリプト
dbusD-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つの工程を踏みます。

  1. 専用ユーザーとグループを作成する(sudo useradd -r -s /bin/false myscriptuser)
  2. 実行ディレクトリを作成し所有者を変更する(sudo mkdir -p /opt/myscript、sudo chown myscriptuser:myscriptuser /opt/myscript)
  3. /etc/systemd/system/myscript.serviceを新規作成する
  4. systemctl daemon-reloadでsystemdに新しいユニットファイルを認識させる
  5. systemctl enable myscript.serviceで自動起動を設定する
  6. systemctl start myscript.serviceでサービスを起動する
  7. 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.target

RestartSec=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.2M

enabledかつ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のように実行します。依存関係のトラブルが疑われるときは、次の順序で切り分けると原因にたどり着きやすくなります。

  1. systemctl list-dependencies myapp.serviceで依存関係を一覧表示する
  2. 依存先サービス(例:postgresql.service)のsystemctl statusを確認する
  3. journalctl -u postgresql.service -bでログを確認する
  4. 循環依存(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/Grouproot権限ではなく専用ユーザーで実行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編集部が各ベンダー公式ドキュメント・エンジニア監修をもとに作成しています。インフラ・クラウド構築は環境により異なります。本番環境への適用前に必ずテストを実施してください。情報の正確性には万全を期していますが、最新情報は各公式ドキュメントをご確認ください。 編集ポリシーはこちら
ABOUT ME
たから
フリーランスIT講師/エンジニア。 ◆経験:IT講師/インフラエンジニア/PM/マネジメント/採用/運用・保守・構築・設計 ◆取得資格:CCNA/CCNP/LPIC-1/AZ-900//サーティファイC言語/情報処理技術者 ◆サイドビジネス:アパレル事業/複数のWEBメディアを運営