XServer API で複数サーバーのディスク使用量を集中監視する

はじめに

複数のクライアントサイトをエックスサーバーで運用していると、「どのサーバーのディスクがどれくらい使われているか」を把握するのが意外と手間になる。管理画面を開いてサーバーごとに確認し、スプレッドシートに転記して…というのを毎回やるのは非効率だ。

エックスサーバーには REST API(XServer API)が用意されており、ディスク使用量などのサーバー情報をプログラムから取得できる。これを使って、1台の管理サーバーから複数のエックスサーバーアカウントを集中監視し、閾値超過をメールで通知する仕組みを PHP で構築した。

この記事ではその設計と実装を紹介する。


XServer API の概要

エックスサーバーのサーバー API(XServer API)のベース URL は https://api.xserver.ne.jp/v1 で、ドメイン・メール・DB・SSL・cron などをプログラムから操作できる。

認証

すべてのリクエストで Bearer トークンを付与する。

curl -H "Authorization: Bearer xs_xxxxxxxxxx" \
  "https://api.xserver.ne.jp/v1/me"

正常に認証できると、以下のようなレスポンスが返る。

{
  "service_type": "server",
  "expires_at": null,
  "servername": "your-server.xsrv.jp",
  "permission_type": "full"
}

ディスク使用量の取得

curl -H "Authorization: Bearer xs_xxxxxxxxxx" \
  "https://api.xserver.ne.jp/v1/server/your-server.xsrv.jp/server-info/usage"
{
  "disk": {
    "quota_gb": 500,
    "used_gb": 239.43,
    "file_limit": 0,
    "file_count": 10886589
  },
  "counts": {
    "domains": 10,
    "subdomains": 87,
    "mail_accounts": 3,
    "mysql_databases": 102
  }
}

ディスク容量・使用量・ファイル数のほか、ドメイン数や DB 数まで一度に取得できる。


アーキテクチャ:集中管理方式

各サーバーにスクリプトを置く方式だと、サーバーが増えるたびに設置・更新が必要になる。今回は1台の管理サーバーが全監視対象の API を呼び出す集中管理方式を採用した。

管理サーバー(monitor.xsrv.jp)
  │
  ├─ cron(毎時)─── disk_check.php ─── server-a.xsrv.jp の API
  │                                  ─── server-b.xsrv.jp の API
  │                                  ─── server-c.xsrv.jp の API
  │
  └─ cron(毎日)─── disk_report.php ── 同上

メリットは次の通り。

  • スクリプトの設置・更新が1か所で済む
  • 監視対象サーバーの追加は設定ファイルへの追記だけ
  • ログ(CSV)も一元管理できる

実装

ファイル構成

xserver_monitor/
├── .env                 # 認証情報(Git 管理外)
├── .env.example         # .env のテンプレート
├── config.php           # 監視対象・閾値・通知設定
├── disk_check.php       # 毎時実行:閾値チェック
├── disk_report.php      # 日次実行:サマリーレポート
├── deploy.sh            # デプロイスクリプト
└── lib/
    ├── Env.php          # .env ローダー
    ├── XServerApi.php   # API クライアント
    ├── CsvLogger.php    # CSV 記録
    └── Notifier.php     # 通知(メール / Chatwork / Slack / Discord)

XServerApi — API クライアント

class XServerApi
{
    private const BASE_URL = 'https://api.xserver.ne.jp/v1';

    public function __construct(
        private string $servername,
        private string $apiKey
    ) {}

    public function getUsage(): array
    {
        return $this->get("/server/{$this->servername}/server-info/usage");
    }

    private function get(string $path): array
    {
        $ch = curl_init(self::BASE_URL . $path);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 30,
            CURLOPT_HTTPHEADER     => [
                "Authorization: Bearer {$this->apiKey}",
                'Accept: application/json',
            ],
        ]);
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        $data = json_decode($response, true);
        if ($httpCode !== 200 || $data === null) {
            throw new RuntimeException("API error [{$this->servername}] HTTP {$httpCode}");
        }
        return $data;
    }
}

CsvLogger — 時系列ログの記録

取得したデータをサーバーごとの CSV ファイルへ追記する。

datetime,quota_gb,used_gb,free_gb,usage_pct,file_count,domains,subdomains,mysql_databases
2024-01-15 10:00:00,500,239.43,260.57,47.9,10886589,10,87,102
2024-01-15 11:00:00,500,239.51,260.49,48.0,10886750,10,87,102

ファイルが存在しない場合はヘッダー行を自動で書き込む。これにより、CSV をそのまま Excel や BI ツールに読み込んで推移を可視化できる。

Notifier — 拡張可能な通知クラス

メール・Chatwork・Slack・Discord に対応し、config.phpenabled フラグで有効化する。

class Notifier
{
    public function send(string $subject, string $body): void
    {
        if (!empty($this->config['email']['enabled']))    $this->sendEmail($subject, $body);
        if (!empty($this->config['chatwork']['enabled'])) $this->sendChatwork($subject, $body);
        if (!empty($this->config['slack']['enabled']))    $this->sendSlack($subject, $body);
        if (!empty($this->config['discord']['enabled']))  $this->sendDiscord($subject, $body);
    }
}

各チャネルは send() を呼ぶだけで一括送信される。新しいチャネルを追加するときも sendXxx() メソッドを追加して send() に組み込むだけでよい。

disk_check.php — 毎時チェック

閾値を超えたときだけ通知する。正常時はサイレント。

foreach ($config['servers'] as $server) {
    $api   = new XServerApi($server['servername'], $server['api_key']);
    $usage = $api->getUsage();
    $row   = $logger->append($server['servername'], $usage);

    if ((float)$row['usage_pct'] >= $server['thresholds']['disk_usage_pct']) {
        $alerts[] = sprintf(
            '[%s] 使用率 %s%% (%sGB / %sGB) ※閾値 %d%% 超過',
            $server['label'], $row['usage_pct'],
            $row['used_gb'], $row['quota_gb'],
            $server['thresholds']['disk_usage_pct']
        );
    }
}

if (!empty($alerts)) {
    $notifier->send('[XServer監視] アラート', implode("\n", $alerts));
}

認証情報の管理:.env パターン

API キーを config.php にハードコードするのは、Git 管理を始めると危険になる。.env ファイルに切り出して Git の管理外に置く方法を採用した。

.env ファイル

XSERVER_API_KEY_MONITOR=xs_xxxxxxxxxx
XSERVER_API_KEY_SERVER_A=xs_xxxxxxxxxx
XSERVER_API_KEY_SERVER_B=xs_xxxxxxxxxx

NOTIFY_SLACK_WEBHOOK_URL=
NOTIFY_DISCORD_WEBHOOK_URL=

.gitignore で除外する。

.env
data/*.csv

Composer 不要の .env ローダー

共有ホスティングでは Composer が使えない場合もある。シンプルな自前実装で対応した。

class Env
{
    public static function load(string $path): void
    {
        foreach (file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
            $line = trim($line);
            if ($line === '' || $line[0] === '#' || !str_contains($line, '=')) continue;

            [$key, $value] = explode('=', $line, 2);
            $value = trim($value, " \"'");

            if (getenv(trim($key)) === false) {
                putenv(trim($key) . '=' . $value);
            }
        }
    }

    public static function require(string $key): string
    {
        $v = getenv($key);
        if ($v === false || $v === '') {
            throw new RuntimeException(".env の必須項目が未設定: {$key}");
        }
        return $v;
    }
}

ポイントは2点。

  1. 既存の環境変数は上書きしない — サーバーの環境変数で上書きできる
  2. require() で必須チェック — APIキーが未設定なら起動時に即エラーになる

config.php 側は以下のように使う。

Env::load(__DIR__ . '/.env');

return [
    'servers' => [
        [
            'servername' => 'your-server.xsrv.jp',
            'api_key'    => Env::require('XSERVER_API_KEY_MONITOR'),
            // ...
        ],
    ],
];

デプロイ:rsync で差分転送

サーバーへの配置は rsync を使う deploy.sh で行う。

rsync -avz --delete \
    --exclude='.env' \
    --exclude='.env.example' \
    --exclude='data/' \
    --exclude='deploy.sh' \
    --exclude='SPEC.md' \
    -e ssh \
    ./ monitor-server:~/shell/xserver_monitor/

--delete でサーバー上の不要ファイルを削除しつつ、.envdata/ はサーバー上のものを保持する。

--dry-run オプションで事前確認もできる。

./deploy.sh --dry-run  # 転送内容を確認するだけ
./deploy.sh            # 本番デプロイ

デプロイ後はリモートで PHP の構文チェックを自動実行し、問題があればすぐに気づける。

ssh monitor-server "php -l ~/shell/xserver_monitor/disk_check.php"

cron の設定:XServer API 経由で自動化

エックスサーバーの cron 設定も XServer API から行える。管理画面を開かずにスクリプトから登録できるのは便利だ。

curl -X POST \
  -H "Authorization: Bearer xs_xxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "minute":  "0",
    "hour":    "*",
    "day":     "*",
    "month":   "*",
    "weekday": "*",
    "command": "/opt/php-8.3/bin/php $HOME/shell/xserver_monitor/disk_check.php",
    "comment": "XServerディスク監視:閾値チェック(毎時)"
  }' \
  "https://api.xserver.ne.jp/v1/server/your-server.xsrv.jp/cron"

登録後は cron ID が返り、PUT / DELETE で変更・削除も API から操作できる。


ドキュメントの整備

運用ツールは「動けばいい」で終わりにしがちだが、後から読み返すとき・引き継ぐときのためにドキュメントを整えた。

クラス仕様・CSV フォーマット・通知メッセージの例・手順書など、実装の根拠となる情報を SPEC.md にまとめた。コードを読まなくても全体像が把握できることを目指した。主な記載内容は以下の通り。

  • 各クラスのメソッド一覧と引数・戻り値
  • CSV カラム定義
  • 通知メッセージのサンプル(件名・本文)
  • サーバー追加・通知チャネル追加の手順
  • 初回セットアップ手順

まとめ

今回構築したシステムの要点を整理する。

項目採用した方法
監視方式管理サーバーから全対象の XServer API を呼ぶ集中管理
認証情報.env に分離・Git 管理外
ログ保存サーバーごとの CSV(将来 JSON 変換も想定)
通知メール / Chatwork / Slack / Discord(有効化切り替え式)
デプロイrsync で差分転送・ドキュメントは除外
cron 設定XServer API 経由
ドキュメントSPEC.md に仕様・手順を集約

XServer API は cron・メール・ドメイン・DNS など広い範囲をカバーしており、今回のディスク監視以外にも応用できる。SSL 証明書の期限監視やドメインの管理自動化など、運用の自動化に活用できそうだ。

今後はディスク使用量の推移グラフ化や、JSON 変換による他システム連携なども検討している。

コメント

タイトルとURLをコピーしました