Linuxサーバーを運用する上で、Webサーバーやデータベースなどのサービス管理は避けて通れません。現在のほとんどのLinuxディストリビューションでは、systemdがサービス管理の中核を担っています。

この記事では、systemdの基本概念からsystemctlコマンドによるサービス制御、Unitファイルの読み方、journalctlによるログ確認、そして自作サービスの登録まで、systemdによるサービス管理を体系的に解説します。

前提条件と動作確認環境

本記事の内容は以下の環境で動作確認しています。

項目 内容
OS Ubuntu 24.04 LTS / AlmaLinux 9
systemd 255
シェル bash 5.2

基本的なLinuxコマンドライン操作ができることを前提としています。WSL2環境でもsystemdを有効化することで利用可能です。

systemdとは

systemdは、Linuxシステムの起動処理とサービス管理を担う初期化システム(initシステム)です。2010年にRed Hatのエンジニアによって開発が始まり、現在ではUbuntu、Debian、CentOS、Fedora、Arch Linuxなど、主要なディストリビューションの標準として採用されています。

従来のinit(SysVinit)との違い

systemd登場以前は、SysVinitが長年にわたってLinuxの初期化システムとして使われていました。両者の主な違いを見てみましょう。

項目 SysVinit systemd
起動方式 順次起動(シーケンシャル) 並列起動(パラレル)
設定ファイル シェルスクリプト 宣言的なUnitファイル
依存関係 番号順による暗黙的な制御 明示的な依存関係定義
起動速度 遅い 高速
プロセス監視 限定的 cgroupsによる完全な追跡
ログ管理 syslog別管理 journald統合
graph TB
    subgraph SysVinit
        A1[カーネル] --> A2[init]
        A2 --> A3[S01script]
        A3 --> A4[S02script]
        A4 --> A5[S03script]
        A5 --> A6[...]
    end
    
    subgraph systemd
        B1[カーネル] --> B2[systemd]
        B2 --> B3[service1]
        B2 --> B4[service2]
        B2 --> B5[service3]
        B3 --> B6[依存サービス]
    end

systemdの並列起動により、システムの起動時間が大幅に短縮されます。また、依存関係を明示的に定義できるため、サービス間の関係が明確になります。

systemdの主要コンポーネント

systemdは単なる初期化システムではなく、複数のコンポーネントから構成される包括的なシステム管理スイートです。

コンポーネント 役割
systemd PID 1として動作するメインプロセス
systemctl サービス管理のためのコマンドラインツール
journald ログ収集・管理デーモン
journalctl journaldのログを閲覧するツール
logind ログインセッション管理
networkd ネットワーク設定管理
resolved DNS解決
timedatectl 日時設定管理

Unit(ユニット)の概念

systemdでは、管理対象のリソースを「Unit(ユニット)」という単位で扱います。サービスだけでなく、マウントポイントやデバイス、タイマーなども含まれます。

Unitの種類

主要なUnitタイプを理解しておきましょう。

Unitタイプ 拡張子 説明
Service .service デーモンやバックグラウンドプロセス
Socket .socket ソケットベースのアクティベーション
Target .target 複数Unitのグループ化(旧ランレベル相当)
Mount .mount ファイルシステムのマウントポイント
Timer .timer タイマーベースのスケジュール実行
Device .device udevデバイス
Path .path ファイルシステムパスの監視
Slice .slice リソース管理グループ

日常的なサービス管理では、主に.serviceを扱います。定期実行には.timerが使われます。

Unitファイルの配置場所

Unitファイルは複数の場所に配置でき、優先順位が定められています。

パス 優先度 用途
/etc/systemd/system/ 最高 管理者が作成・カスタマイズするUnit
/run/systemd/system/ ランタイムで生成される一時的なUnit
/usr/lib/systemd/system/ パッケージがインストールするUnit

カスタマイズする際は、/etc/systemd/system/にファイルを配置します。同名のUnitファイルが複数の場所にある場合、優先度の高いものが使用されます。

systemctlによるサービス管理

systemctlは、systemdを操作するためのメインコマンドです。サービスの起動・停止・状態確認など、日常的な管理作業のほとんどをsystemctlで行います。

サービスの状態確認(status)

サービスの現在の状態を確認するには、systemctl statusを使用します。

1
systemctl status nginx

出力例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: disabled)
     Active: active (running) since Wed 2026-01-08 10:00:00 JST; 2h ago
       Docs: man:nginx(8)
    Process: 1234 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
   Main PID: 1235 (nginx)
      Tasks: 3 (limit: 4647)
     Memory: 5.2M
        CPU: 32ms
     CGroup: /system.slice/nginx.service
             ├─1235 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             ├─1236 "nginx: worker process"
             └─1237 "nginx: worker process"

Jan 08 10:00:00 server systemd[1]: Starting nginx.service - A high performance web server...
Jan 08 10:00:00 server systemd[1]: Started nginx.service - A high performance web server...

statusコマンドの出力には、重要な情報が含まれています。

フィールド 説明
Loaded Unitファイルの読み込み状態と自動起動設定
Active サービスの実行状態(active/inactive/failed)
Main PID メインプロセスのPID
Tasks 起動しているタスク数
Memory メモリ使用量
CGroup コントロールグループのプロセスツリー

先頭の「●」の色にも意味があります。緑は正常動作中、赤は失敗、白は非アクティブを示します。

サービスの起動と停止

サービスを起動するにはstart、停止するにはstopを使用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# サービスの起動
sudo systemctl start nginx

# サービスの停止
sudo systemctl stop nginx

# サービスの再起動(stop + start)
sudo systemctl restart nginx

# 設定ファイルの再読み込み(プロセス再起動なし)
sudo systemctl reload nginx

# reload可能ならreload、不可ならrestart
sudo systemctl reload-or-restart nginx

restartreloadの使い分けは重要です。

コマンド 動作 ダウンタイム
restart プロセスを停止して再起動 あり(短い)
reload プロセス維持のまま設定再読み込み なし

設定変更後は、可能であればreloadを使用することで、サービスの継続性を保てます。ただし、すべてのサービスがreloadに対応しているわけではありません。

自動起動の設定(enable/disable)

システム起動時にサービスを自動的に開始させるには、enableを使用します。

1
2
3
4
5
6
7
8
# 自動起動を有効化
sudo systemctl enable nginx

# 自動起動を無効化
sudo systemctl disable nginx

# 自動起動設定の確認
systemctl is-enabled nginx

enableコマンドは、指定したUnitファイルへのシンボリックリンクを/etc/systemd/system/配下に作成します。

1
2
# enableの実行結果例
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.

enablestartを同時に行うこともできます。

1
2
3
4
5
# 自動起動有効化と即時起動を同時実行
sudo systemctl enable --now nginx

# 自動起動無効化と即時停止を同時実行
sudo systemctl disable --now nginx

サービス一覧の表示

システム上のサービス一覧を確認するには、list-unitsまたはlist-unit-filesを使用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 現在ロードされているUnitの一覧(serviceのみ)
systemctl list-units --type=service

# すべてのUnitファイルの一覧
systemctl list-unit-files --type=service

# 実行中のサービスのみ表示
systemctl list-units --type=service --state=running

# 失敗したサービスを表示
systemctl list-units --type=service --state=failed

list-unit-filesの出力例:

1
2
3
4
5
UNIT FILE                              STATE           PRESET
nginx.service                          enabled         disabled
postgresql.service                     enabled         disabled
ssh.service                            enabled         enabled
cron.service                           enabled         enabled

STATEカラムの意味:

状態 説明
enabled 自動起動が有効
disabled 自動起動が無効
static 他のUnitからのみ起動される
masked 完全に無効化されている

サービスの完全無効化(mask)

disableはシンボリックリンクを削除するだけですが、maskを使うと他のUnitからの依存関係による起動も含めて完全に無効化できます。

1
2
3
4
5
# 完全に無効化
sudo systemctl mask nginx

# 無効化を解除
sudo systemctl unmask nginx

maskは、Unitファイルを/dev/nullへのシンボリックリンクに置き換えることで実現されています。

Unitファイルの読み方と構造

systemdのサービスを深く理解するには、Unitファイルの構造を知る必要があります。ここでは、実際のUnitファイルを読み解いてみましょう。

基本的なUnitファイルの構造

Unitファイルはセクションに分かれており、それぞれにディレクティブ(設定項目)を記述します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[Unit]
# Unitの説明とメタデータ
Description=サービスの説明
Documentation=man:nginx(8)
After=network.target

[Service]
# サービス固有の設定
Type=forking
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID

[Install]
# インストール(enable時)の設定
WantedBy=multi-user.target

[Unit]セクション

[Unit]セクションには、サービスの説明と依存関係を記述します。

ディレクティブ 説明
Description サービスの説明文
Documentation ドキュメントへの参照
After このUnitより先に起動すべきUnit
Before このUnitより後に起動すべきUnit
Requires 必須の依存Unit(失敗時は自分も停止)
Wants 推奨の依存Unit(失敗しても継続)
Conflicts 同時に実行できないUnit

After/Beforeは起動順序のみを制御し、Requires/Wantsは依存関係を定義します。両方を組み合わせて使用することが一般的です。

1
2
3
4
5
6
7
[Unit]
Description=My Application
# networkが起動してから起動する
After=network.target
# postgresqlが必要(失敗時は自分も起動しない)
Requires=postgresql.service
After=postgresql.service

[Service]セクション

[Service]セクションには、サービスの実行方法を記述します。

主要なディレクティブ:

ディレクティブ 説明
Type サービスタイプ(後述)
ExecStart 起動時に実行するコマンド
ExecStop 停止時に実行するコマンド
ExecReload reload時に実行するコマンド
Restart プロセス終了時の再起動条件
RestartSec 再起動までの待機秒数
User 実行ユーザー
Group 実行グループ
WorkingDirectory 作業ディレクトリ
Environment 環境変数
EnvironmentFile 環境変数ファイル

Typeディレクティブの種類

Typeはサービスの起動方式を指定します。適切なTypeを選択することが重要です。

Type 説明 代表例
simple ExecStartがメインプロセス(デフォルト) 一般的なデーモン
forking fork後に親プロセスが終了 nginx、Apache(従来型)
oneshot 完了まで待機(1回実行) 初期化スクリプト
notify 起動完了をsystemdに通知 PostgreSQL
dbus D-Bus名の取得で起動完了と判断 D-Bus対応サービス
idle 他のジョブ完了後に実行 優先度の低いサービス
graph LR
    subgraph "Type=simple"
        A1[systemctl start] --> A2[ExecStart実行]
        A2 --> A3[即座に起動完了と判断]
    end
    
    subgraph "Type=forking"
        B1[systemctl start] --> B2[ExecStart実行]
        B2 --> B3[親プロセスfork]
        B3 --> B4[親プロセス終了]
        B4 --> B5[起動完了と判断]
    end
    
    subgraph "Type=notify"
        C1[systemctl start] --> C2[ExecStart実行]
        C2 --> C3[初期化処理]
        C3 --> C4[sd_notify送信]
        C4 --> C5[起動完了と判断]
    end

Restartディレクティブの設定

プロセスが異常終了した場合の自動再起動を設定できます。

説明
no 再起動しない(デフォルト)
on-success 正常終了時のみ再起動
on-failure 異常終了時のみ再起動
on-abnormal シグナル・タイムアウト時に再起動
on-abort キャッチされないシグナル時に再起動
always 常に再起動
1
2
3
4
5
6
7
8
9
[Service]
Type=simple
ExecStart=/usr/bin/myapp
# 異常終了時は5秒後に再起動
Restart=on-failure
RestartSec=5
# 再起動試行の制限(10秒間に3回まで)
StartLimitBurst=3
StartLimitIntervalSec=10

[Install]セクション

[Install]セクションは、systemctl enable実行時の動作を定義します。

ディレクティブ 説明
WantedBy enableでシンボリックリンクを作成するtarget
RequiredBy enable時に必須としてリンクを作成するtarget
Also enableで一緒にenableするUnit
Alias Unitの別名
1
2
3
[Install]
# マルチユーザーモード(通常起動)で有効化
WantedBy=multi-user.target

WantedBy=multi-user.targetは最も一般的な設定で、通常のLinux起動時にサービスを開始することを意味します。

実際のUnitファイル例

実運用されているnginxのUnitファイルを見てみましょう。

1
systemctl cat nginx
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# /usr/lib/systemd/system/nginx.service
[Unit]
Description=A high performance web server and a reverse proxy server
Documentation=man:nginx(8)
After=network.target remote-fs.target nss-lookup.target
StartLimitIntervalSec=0

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

このUnitファイルから読み取れる内容:

  1. After=network.target: ネットワーク起動後に開始
  2. Type=forking: 起動時にforkするタイプ
  3. ExecStartPre: 起動前に設定ファイルの構文チェック
  4. PIDFile: PIDファイルの場所を指定
  5. PrivateTmp=true: 専用の/tmpディレクトリを使用(セキュリティ強化)

journalctlによるログ確認

systemdには、ログ管理システムであるjournaldが統合されています。journalctlコマンドを使用して、システムおよびサービスのログを確認できます。

基本的なログ確認

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# すべてのログを表示
journalctl

# 末尾から表示(最新ログ)
journalctl -e

# 直近のn行を表示
journalctl -n 50

# リアルタイムでログを追跡
journalctl -f

サービスのログをフィルタリング

特定のサービスのログのみを表示するには、-uオプションを使用します。

1
2
3
4
5
6
7
8
# nginxのログを表示
journalctl -u nginx

# nginxのログをリアルタイム追跡
journalctl -u nginx -f

# 複数サービスのログ
journalctl -u nginx -u postgresql

時間でフィルタリング

特定の時間範囲のログを確認することもできます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 今日のログ
journalctl --since today

# 直近1時間のログ
journalctl --since "1 hour ago"

# 特定期間のログ
journalctl --since "2026-01-08 10:00:00" --until "2026-01-08 12:00:00"

# 前回起動時のログ
journalctl -b -1

# 今回起動以降のログ
journalctl -b

優先度でフィルタリング

ログの重要度(優先度)でフィルタリングできます。

1
2
3
4
5
# エラー以上のログ
journalctl -p err

# 警告以上のログ
journalctl -p warning

優先度レベル:

レベル 意味
emerg (0) 緊急
alert (1) 警報
crit (2) 致命的
err (3) エラー
warning (4) 警告
notice (5) 通知
info (6) 情報
debug (7) デバッグ

出力形式の変更

1
2
3
4
5
6
7
8
# JSON形式で出力
journalctl -u nginx -o json-pretty

# 詳細形式で出力
journalctl -u nginx -o verbose

# 短い形式(デフォルト)
journalctl -u nginx -o short

ディスク使用量の確認と管理

journalのログはディスク容量を消費するため、定期的な管理が必要です。

1
2
3
4
5
6
7
8
# ディスク使用量の確認
journalctl --disk-usage

# 古いログの削除(サイズ指定)
sudo journalctl --vacuum-size=500M

# 古いログの削除(日数指定)
sudo journalctl --vacuum-time=7d

自作サービスの登録

独自のアプリケーションをsystemdサービスとして登録する方法を解説します。

シンプルなサービスの作成

例として、Node.jsアプリケーションをサービス化してみましょう。

まず、Unitファイルを作成します。

1
sudo vim /etc/systemd/system/myapp.service
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[Unit]
Description=My Node.js Application
Documentation=https://example.com/docs
After=network.target

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/node /var/www/myapp/server.js
Restart=on-failure
RestartSec=10

# 環境変数
Environment=NODE_ENV=production
Environment=PORT=3000

# セキュリティ設定
NoNewPrivileges=true
PrivateTmp=true

# ログ設定
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

サービスの有効化と起動

Unitファイルを作成または変更した後は、systemdにリロードを指示する必要があります。

1
2
3
4
5
6
7
8
# systemdに設定を再読み込み
sudo systemctl daemon-reload

# サービスの有効化と起動
sudo systemctl enable --now myapp

# 状態確認
systemctl status myapp

環境変数ファイルの使用

機密情報を含む環境変数は、別ファイルに分離することをお勧めします。

1
sudo vim /etc/myapp/env
1
2
3
4
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://user:pass@localhost/mydb
SECRET_KEY=your-secret-key

Unitファイルでファイルを参照:

1
2
3
[Service]
EnvironmentFile=/etc/myapp/env
ExecStart=/usr/bin/node /var/www/myapp/server.js

起動スクリプトを使用する例

より複雑な起動処理が必要な場合は、ラッパースクリプトを使用します。

1
sudo vim /usr/local/bin/myapp-start.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/bin/bash
set -e

cd /var/www/myapp

# 環境のセットアップ
export PATH="/usr/local/bin:$PATH"

# 依存関係の確認
if [ ! -d "node_modules" ]; then
    npm install --production
fi

# アプリケーション起動
exec node server.js
1
sudo chmod +x /usr/local/bin/myapp-start.sh

Unitファイル:

1
2
3
[Service]
Type=simple
ExecStart=/usr/local/bin/myapp-start.sh

セキュリティ強化オプション

本番環境では、セキュリティを強化するオプションを追加することをお勧めします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[Service]
# 特権昇格の禁止
NoNewPrivileges=true

# 専用のtmpディレクトリ
PrivateTmp=true

# ホームディレクトリへのアクセス制限
ProtectHome=true

# システムディレクトリを読み取り専用に
ProtectSystem=strict

# 書き込み可能なディレクトリを明示
ReadWritePaths=/var/www/myapp/data /var/log/myapp

# ネットワーク名前空間の制限
PrivateNetwork=false

# デバイスへのアクセス制限
PrivateDevices=true

# カーネルチューナブルの変更禁止
ProtectKernelTunables=true

# カーネルモジュールのロード禁止
ProtectKernelModules=true

実践的なトラブルシューティング

systemdでサービス管理を行う際によくある問題とその解決方法を紹介します。

サービスが起動しない場合

  1. 状態を確認する
1
systemctl status myapp
  1. 詳細なログを確認する
1
journalctl -u myapp -n 50 --no-pager
  1. 設定ファイルの構文をチェックする
1
systemd-analyze verify /etc/systemd/system/myapp.service

よくあるエラーと対処法

エラー 原因 対処法
code=exited, status=203/EXEC 実行ファイルが見つからない ExecStartのパスを確認
code=exited, status=217/USER 指定ユーザーが存在しない User/Groupの設定を確認
code=exited, status=200/CHDIR 作業ディレクトリが存在しない WorkingDirectoryを確認
code=exited, status=1/FAILURE アプリケーションエラー journalctlでログを確認

依存関係の確認

サービスの依存関係を確認するには:

1
2
3
4
5
# 依存関係ツリーを表示
systemctl list-dependencies nginx

# 逆依存関係(このUnitに依存しているUnit)
systemctl list-dependencies nginx --reverse

起動時間の分析

システムの起動時間やサービスごとの起動時間を分析:

1
2
3
4
5
6
7
8
# 起動時間の概要
systemd-analyze

# サービスごとの起動時間
systemd-analyze blame

# 起動の時系列グラフを生成
systemd-analyze plot > boot-analysis.svg

まとめ

systemdは現代のLinuxシステムにおけるサービス管理の標準です。この記事では以下の内容を解説しました。

  • systemdの基本概念と従来のSysVinitとの違い
  • systemctlコマンドによるサービス制御(start/stop/restart/status/enable/disable)
  • Unitファイルの構造と各セクションの役割
  • journalctlによるログ確認とフィルタリング
  • 自作サービスの登録方法とセキュリティ設定

systemdを使いこなすことで、サービスの起動・停止、自動起動設定、ログ確認、トラブルシューティングを効率的に行えるようになります。まずは日常的に使用するサービスでsystemctl statusjournalctlを試し、徐々にカスタムサービスの作成にも挑戦してみてください。

参考リンク