5分でわかる — 毎日使うsystemdコマンド
Linuxサーバーを始めたばかりですか?これは意識しなくても自然に覚えてしまうほど頻繁に使う5つのコマンドです:
# サービスのステータスを確認する
systemctl status nginx
# 起動 / 停止 / 再起動
systemctl start nginx
systemctl stop nginx
systemctl restart nginx
# 起動時の自動起動を有効化 / 無効化
systemctl enable nginx
systemctl disable nginx
# 再起動せずに設定をリロード(サービスがサポートしている場合)
systemctl reload nginx
さっそくnginxや手元にあるサービスで試してみましょう。緑色のactive (running)なら正常、赤色のfailedなら問題あり — 非常に直感的で、ドキュメントを読まなくてもわかります。
systemdの仕組みを理解する
SysVinit の後継として登場したsystemdは、現在Ubuntu、Debian、CentOS/AlmaLinux、FedoraなどほぼすべてのLinuxディストリビューションでデフォルトのinitシステムになっています。旧世代との最大の違いは、並列起動、サービス間の依存関係管理、そして/var/log/に散在していたログをジャーナルに一元管理できる点です。
systemdが管理するものはすべてunitと呼ばれます。最もよく使う4種類を紹介します:
.service— バックグラウンドプロセス(nginx、mysql、sshdなど).timer— cronに似た定期タスクの実行.socket— ソケットアクティベーション(接続があった時だけサービスを起動).mount— マウントポイントの管理
ユニットファイルは主に2か所に存在します:
/lib/systemd/system/— パッケージマネージャーがインストール、直接編集は避ける/etc/systemd/system/— オーバーライドや新規作成用、ここが作業場所
アプリケーション用のカスタムsystemdサービスを作成する
これが私が最もよく使う部分です。PythonやNode.jsのスクリプトをサーバーにデプロイするたびに必ずサービスファイルを作成します — nohupやscreenはもう使いません。
例:ポート8000で動くPythonアプリケーションをデプロイする場合:
sudo nano /etc/systemd/system/myapp.service
[Unit]
Description=My Python App
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/myapp
ExecStart=/home/ubuntu/myapp/venv/bin/python app.py
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
# systemdが新しいファイルを認識するためにリロード
sudo systemctl daemon-reload
# 有効化して起動
sudo systemctl enable --now myapp
Restart=on-failureに注目してください — クラッシュ時にサービスが自動的に再起動します。先月、私のサービスが深夜2時にクラッシュしましたが、5秒以内に自動復旧し、翌朝ログを見るまで気づきませんでした。夜中にSSH接続して対応する必要はありませんでした。
よく使うRestartの値
no— 自動再起動しない(デフォルト)on-failure— 終了コードが0以外の時に再起動always— 手動でsystemctl stopした場合でも常に再起動on-abnormal— シグナルでkillされた時に再起動
99%のケースではon-failureを使いましょう。alwaysは安全に聞こえますが、アプリが起動直後に失敗すると無限ループになります — systemdは制限に達するまで再起動を試みた後、failedとマークします。
サービスが失敗したときのデバッグ
サービスがfailedと表示されましたか?慌てないでください。私のデバッグ手順:
# 詳細なステータスと最後の数行のログを表示
systemctl status myapp -l
# サービスのすべてのログを表示
journalctl -u myapp
# リアルタイムでログを表示(ライブ監視)
journalctl -u myapp -f
# 今回の起動からのログのみ表示
journalctl -u myapp -b
# 最後の50行
journalctl -u myapp -n 50
journalctlはすべてのログをタイムスタンプ付きで一か所に集約し、ユニットや時間でフィルタリングできます。これに慣れてからはtail -f /var/log/...の習慣をすっかりやめました。
最もよくある間違い:.serviceファイルを編集した後にdaemon-reloadを実行し忘れることです。systemdはキャッシュ内の古いバージョンを使い続けるため、変更が反映されません。ファイルを編集するたびに必ずリロードしてください — 例外はありません。
応用編 — 元のファイルを変更せずにサービスをオーバーライドする
実際のシナリオ:nginxのファイルディスクリプタ上限を65536に増やしたい(デフォルトは1024)が、apt upgradeで上書きされてしまうため/lib/systemd/system/nginx.serviceを直接編集したくない場合。
# editコマンドを使用 — オーバーライドディレクトリを自動作成
sudo systemctl edit nginx
上記のコマンドはエディタを開き、/etc/systemd/system/nginx.service.d/override.confにファイルを作成します。変更したい部分だけ記述すれば十分です:
[Service]
LimitNOFILE=65536
Environment="EXTRA_OPTS=-g 'worker_processes 4;'"
すべてのオーバーライドを結合した最終結果を確認したい場合:
systemctl cat nginx
cgroupsでリソースを制限する
cgroupsはあまり知られていませんが非常に便利な機能です — systemdに統合されており、各サービスのCPUとRAMを制限できます:
[Service]
# 最大512MB RAMに制限
MemoryMax=512M
# CPU使用率を50%に制限
CPUQuota=50%
# CPU優先度を下げる(デフォルト100)
CPUWeight=50
2GB RAMのVPSで5〜6個のサービスを同時に動かしている環境では、これが安心して眠れる理由です — 一つのサービスがリソースを食い尽くしてシステム全体を道連れにする心配がありません。
systemdタイマー — cronより効率的な代替手段
私のcronジョブのほとんどはsystemdタイマーに移行しました。理由はシンプル:デバッグがはるかに簡単です。ログはジャーナルに記録され、最後の実行日時と次の実行日時も確認できます — cronのように/var/log/syslogを探し回る必要がありません。
毎日午前2時にバックアップスクリプトを実行する例:
sudo nano /etc/systemd/system/backup.service
[Unit]
Description=Daily backup script
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 2am
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl enable --now backup.timer
# すべてのタイマーとステータスを表示
systemctl list-timers
Persistent=trueは、サーバーが午前2時に停止していてスケジュールを逃した場合に対処します — 翌夜まで待つのではなく、サーバーが再起動したらすぐにタイマーが補完実行されます。
運用経験から得た実践的なTips
1. --nowを使って有効化と起動を同時に行う
systemctl enable --now myapp
# 同等:
systemctl enable myapp && systemctl start myapp
2. 失敗中のすべてのサービスを確認する
systemctl --failed
サーバーリブート後に最初に実行するコマンドです。失敗しているサービスがあればすぐにわかります — 一つひとつ確認する必要がありません。
3. 起動時間を分析する
systemd-analyze blame | head -20
起動に最も時間がかかるサービスを一覧表示します。私の開発マシンでは、snapdが30秒以上かかっていました — 無効にしたことで、起動時間が45秒から12秒に短縮されました。
4. 専用ユーザーでサービスを実行する(セキュリティ)
必要でない限り、rootでサービスを実行しないでください。専用ユーザーを作成します:
sudo useradd -r -s /bin/false myappuser
[Service]
User=myappuser
Group=myappuser
# 必要に応じてサンドボックスを追加
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
5. ExecStartPre / ExecStartPost
サービス起動前にコマンドを実行します — 例えば、データベースが起動中ではなく本当に準備完了するまで待つ場合:
[Service]
ExecStartPre=/bin/sh -c 'until pg_isready -h localhost; do sleep 1; done'
ExecStart=/home/ubuntu/myapp/venv/bin/python app.py
この方法はAfter=postgresql.serviceより優れています。Afterは起動順序を保証するだけで、postgresが接続を受け付けられる状態かは保証しないからです。以前、アプリが先に起動してしまい、postgresがまだウォームアップ中で最初から接続が失敗するというエラーを経験したことがあります。

