systemd service生成ツール

[Unit] セクション
[Service] セクション
Restart設定
オプション
[Install] セクション

systemd serviceの概要・基礎知識

systemdは現代の主要なLinuxディストリビューション(Ubuntu・Debian・RHEL系・Arch等)が採用するinitシステムで、サーバープロセスやバッチジョブを「ユニット」と呼ばれる単位で管理します。本ツールはWebアプリやワーカーを常駐化する際に必要な「.service」ユニットファイルを、Description・ExecStart・User・Restart・PrivateTmp等のフォーム入力からまとめて生成します。手書きで起きがちな構文ミス([Service]忘れ・改行抜け・パスの相対指定)を防ぎ、/etc/systemd/system/に置いてすぐ使える形で出力する設計です。本番運用に必要なセキュリティオプション(PrivateTmp / ProtectSystem / リソース制限)にも対応しています。

セクションと主要ディレクティブ

セクションディレクティブ役割
[Unit]Description / After / Wants説明と起動順序
[Service]Type / ExecStart / User / Groupプロセス起動方法
[Service]Restart / RestartSec異常終了時の再起動制御
[Service]Environment / EnvironmentFile環境変数の注入
[Service]PrivateTmp / ProtectSystemセキュリティ強化
[Install]WantedBy有効化時の依存先

Typeの選択は重要で、simpleは最も汎用、forkingは古典的なデーモン、oneshotは単発スクリプト、notifyはsd_notify()対応アプリで使い分けます。

使い方の流れ

  1. [Unit]セクションでDescription(サービス説明)と After(依存サービス。通常はnetwork.target)を入力します。Wantsは「望ましい依存」で、network-online.targetを指定するとオンライン到達後に起動します。
  2. [Service]セクションでTypeを選び、ExecStartにフルパスで起動コマンドを書きます。例: /usr/bin/node /opt/myapp/index.js。User・Group・WorkingDirectoryも本番では明示が推奨です。
  3. 環境変数はKEY=VALUEを改行区切りで入力するか、別ファイル(EnvironmentFile)で外部化します。秘密値は専用ファイル+chmod 600が原則です。
  4. Restartはサーバー系ならalways、バッチ系ならon-failureを選び、RestartSecで再試行間隔(秒)を指定します。
  5. 「生成する」を押すとユニットファイル本体と、設置・有効化用のコマンド(cp / daemon-reload / enable / start)がまとめて出力されます。

こんな場面で使う

  • 自作Webアプリの常駐化:Node.js / Pythonで作ったサーバーをVPS上で永続稼働させ、再起動時に自動立ち上げするユニットを素早く整備できます。
  • バッチジョブの自動再試行:Type=oneshot+Restart=on-failureで、cronより細かい挙動制御を実現できます。
  • 本番セキュリティ強化:PrivateTmp / ProtectSystem / NoNewPrivileges 等を有効にしたテンプレートで、セキュリティ要件をテンプレ化できます。
  • OSSのインストールガイド作成:READMEに「以下のserviceファイルを作成してください」と貼れる、一貫したフォーマットを提供できます。
  • Ansible/Chefのテンプレート整備:構成管理ツール向けJinja2テンプレートの土台として、生成結果を流用できます。

使う前に知っておきたい注意点

  • ユニットファイルは必ず/etc/systemd/system/に配置し、sudo systemctl daemon-reloadで再読み込み後に enable / startします。Read-onlyの/lib/systemd/system/には置かないでください(パッケージで上書きされる恐れ)。
  • ExecStartは絶対パス指定が必須です。node app.jsのような相対指定は失敗します。which nodeでフルパスを確認してください。
  • シェルパイプやリダイレクトは直接書けません。bash -c "..."でラップするか、ログをsyslog経由(StandardOutput=journal)で扱うのが正攻法です。
  • Restart=alwaysは強力ですが、起動直後に毎回失敗するアプリだと無限再起動ループになります。StartLimitIntervalSec / StartLimitBurstでブレーキも併用してください。
  • ProtectSystem=fullは/usr/bootを読み取り専用化します。アプリが書き込みを必要とするディレクトリはReadWritePaths=で許可リストに追加してください。

用語の補足

  • journal:systemdのログ統合機能。journalctl -u myapp.service -fでリアルタイム追跡できます。
  • target:複数ユニットの依存関係をまとめる単位。multi-user.targetはいわゆる「マルチユーザー起動状態」です。
  • drop-in/etc/systemd/system/myapp.service.d/に置く設定追加ファイル。元ファイルを直接編集せずに上書き設定できます。

よくある質問

/etc/systemd/system/ に配置するのが標準です。配置後、sudo systemctl daemon-reloadで再読み込み、sudo systemctl enable --now myappで有効化+起動します。/lib/systemd/system/はディストリビューション側の領域なので、独自ユニットを置かないでください。
セキュリティ強化のため、可能な限り有効にすることを推奨します。ProtectSystem=full/usr/bootを読み取り専用化、PrivateTmp=trueはサービス専用の/tmp名前空間を提供します。アプリが書き込み必要なディレクトリはReadWritePaths=でホワイトリスト指定してください。
journalctl -u myapp.serviceでログを確認できます。-fでリアルタイム追跡、--since "1 hour ago"で時間指定の絞り込みが可能です。アプリ側で標準出力・標準エラーに書いた内容はそのままjournalに記録されます。
まずsystemctl status myapp.serviceで直近の状態を確認し、続いてjournalctl -u myapp.service -eで末尾ログを見ます。よくある原因はExecStartの相対パス指定、Userの存在しないアカウント指定、WorkingDirectoryの権限不足です。systemd-analyze verify myapp.serviceで構文チェックも可能です。
公開してよい設定値(NODE_ENV=production等)はユニット内のEnvironment=で十分です。APIキーやDBパスワードのような機密値はEnvironmentFile=/etc/myapp/envで外部ファイル化し、chmod 600で権限を絞るのが標準的です。
現代的なアプリ(Node.js / Python / Go)はsimpleが最適です。アプリ自身がフォアグラウンドで動き、systemdが直接プロセスを監視できます。forkingは古典的なデーモン(Apache 2.2系等)で必要ですが、PIDFileの設定漏れで誤動作しやすいので、可能ならsimpleに寄せるのが安全です。
いいえ、すべての生成処理はブラウザ上で完結し、入力したパスや環境変数値が外部のサーバーに送信されることはありません。本番環境の構成を含む値も安全に取り扱えます。