Nova Uptime
ガイドwebhooksautomationintegrations

アップタイムモニタリングのwebhookとintegration:カスタムワークフローを構築する

webhookでアップタイムモニタリングを自社システムに接続。インシデント自動化、カスタム通知、ワークフローintegrationパターンの完全ガイド。 — Nova Uptimeはアップタイム、SSL、メール健全性、リンク変更を1つのダッシュボードで監視します。

SN
Sumit Nova Uptime
2026年2月27日 · 11 min read
Share:

モニタリングにおいてwebhookが重要な理由#

メールアラートはいずれ届きます。Slackアラートはチャンネルに表示されます。しかしwebhookを使えば、インシデント発生時に実際のアクションを実行できます。

webhookがない場合:

  • アラート発生 → 手動でJiraチケットを作成 → 手動でステータスページを更新 → 手動でオンコール担当者を呼び出し
  • 対応時間:5〜10分

webhookがある場合:

  • アラート発生 → webhookが起動 → 自動でJiraチケットを作成 → ステータスページを更新 → オンコール担当者を呼び出し
  • 対応時間:10秒

クリティカルなインフラでは、この5分の差が顧客への影響を防ぎます。

webhookの仕組み#

サイトがダウンし、モニタリングがそれを検知すると:

1. Nova Uptimeのモニタリングサービスが障害を検知
2. Nova UptimeがインシデントデータをあなたのwebhookのURLに送信
3. あなたのサーバーが以下を含むHTTP POSTを受信:
   - ドメイン
   - ステータス
   - 検知時刻
   - 応答時間
   - 前回のチェック結果
4. あなたのシステムが処理内容を判断
   - Jiraチケットを作成?
   - オンコール担当者を呼び出し?
   - ステータスページを更新?
   - Slackに投稿?
5. アクションが自動実行される

webhookの設定方法#

ステップ1:webhookレシーバーを作成する#

webhookレシーバーは、インシデントデータを受信するシンプルなHTTPエンドポイントです。

例:Express.jsによるwebhookレシーバー

const express = require('express');
const app = express();

app.use(express.json());

app.post('/webhooks/uptime-incident', async (req, res) => {
  const { domain, status, detectedAt, responseTime } = req.body;

  console.log(`Incident detected: ${domain} is ${status}`);

  // Handle the incident
  await handleIncident({
    domain,
    status,
    detectedAt,
    responseTime
  });

  // Respond with 200 OK to acknowledge receipt
  res.json({ success: true });
});

app.listen(3000, () => {
  console.log('Webhook receiver listening on port 3000');
});

ステップ2:Nova Uptimeでwebhookを設定する#

  1. go.novauptime.comにログインします
  2. ドメイン設定 → Webhooks
  3. 「Add Webhook」をクリック
  4. エンドポイントURLを入力:https://yourdomain.com/webhooks/uptime-incident
  5. トリガーするイベントを選択:
    • ✅ サイトダウン
    • ✅ サイト復旧
    • ✅ 応答時間の警告
  6. 保存

ステップ3:webhookをテストする#

ほとんどのツールには「Test Webhook」ボタンがあります:

  1. webhook設定の「Test」をクリック
  2. エンドポイントがテストデータを受信
  3. システムが200 OKで応答することを確認

実践的なwebhookパターン#

パターン1:インシデントチケットを作成する#

サイトがダウンしたら、自動でJiraチケットを作成します。

async function handleIncident({ domain, status, detectedAt }) {
  if (status === 'down') {
    // Create Jira ticket
    const ticket = await createJiraTicket({
      project: 'OPS',
      issueType: 'Incident',
      summary: `Production Incident: ${domain} is down`,
      description: `
        Domain: ${domain}
        Detected: ${detectedAt}
        Status: DOWN

        Actions:
        1. Check server status
        2. Review recent deployments
        3. Check error logs
      `,
      priority: 'Critical',
      labels: ['incident', 'production']
    });

    console.log(`Created ticket: ${ticket.key}`);
  }
}

パターン2:ステータスページを更新する#

インシデント発生時に、公開ステータスページを自動更新します。

async function handleIncident({ domain, status, detectedAt }) {
  if (status === 'down') {
    // Create incident on status page
    await createStatusPageIncident({
      name: `${domain} is Down`,
      status: 'investigating',
      body: `We're investigating an issue with ${domain}. More info coming soon.`,
      affectedComponents: [domain]
    });
  } else if (status === 'up') {
    // Resolve incident on status page
    await updateStatusPageIncident({
      status: 'resolved',
      body: `${domain} is now back online. We apologize for the inconvenience.`
    });
  }
}

パターン3:オンコールエンジニアを呼び出す#

クリティカルなインシデント発生時に、オンコール担当者へ即座にSMSを送信します。

async function handleIncident({ domain, status, detectedAt }) {
  if (status === 'down') {
    // Get current on-call engineer from PagerDuty
    const oncall = await getOnCallEngineer();

    // Send SMS
    await sendSMS({
      to: oncall.phone,
      message: `CRITICAL: ${domain} is down. Incident ticket: JIRA-123`
    });

    // Also post to #incidents Slack channel
    await postToSlack({
      channel: '#incidents',
      text: `@${oncall.slackHandle}: ${domain} is down. See JIRA-123`
    });
  }
}

パターン4:インシデント履歴を保存する#

すべてのインシデントを分析用にデータベースへ記録します。

async function handleIncident({ domain, status, detectedAt, responseTime }) {
  // Store in database
  const incident = await Incident.create({
    domain,
    status,
    detectedAt,
    responseTime,
    createdAt: new Date(),
    handledAt: new Date(),
    ticketCreated: false,
    statusPageUpdated: false
  });

  console.log(`Stored incident: ${incident._id}`);

  // Later: calculate MTTR, uptime %, etc.
  await updateIncidentMetrics(domain);
}

パターン5:複数サービスのオーケストレーション#

1つのサービスに障害が発生したら、複数プラットフォームでアクションを連鎖実行します。

async function handleIncident({ domain, status, detectedAt }) {
  if (status === 'down') {
    // Parallel actions: Don't wait for each to finish
    await Promise.all([
      createJiraTicket({ domain, status }),
      createStatusPageIncident({ domain }),
      pageOnCallEngineer({ domain }),
      postSlackAlert({ domain }),
      storeIncidentHistory({ domain, detectedAt }),
      triggerPostmortemWorkflow({ domain })
    ]);
  }
}

高度なパターン

パターン6:重大度に応じた条件分岐#

重大度レベルごとに異なるアクションを実行します。

async function handleIncident({ domain, status, severity }) {
  if (severity === 'critical') {
    // Critical: Page everyone
    await pageOnCall({ priority: 'high' });
    await updateStatusPage({ status: 'major_outage' });
    await createJiraTicket({ priority: 'Critical' });
  } else if (severity === 'warning') {
    // Warning: Slack + Jira, no SMS
    await postSlackAlert({ channel: '#alerts' });
    await createJiraTicket({ priority: 'Medium' });
  } else if (severity === 'info') {
    // Info: Log only, no alert
    await storeIncidentHistory({ domain });
  }
}

パターン7:重複排除#

同じドメインが複数回失敗した場合に、チケットやアラートの重複を防ぎます。

async function handleIncident({ domain, status }) {
  if (status === 'down') {
    // Check if active incident already exists
    const activeIncident = await Incident.findOne({
      domain,
      status: 'active',
      createdAfter: new Date(Date.now() - 15 * 60 * 1000) // Last 15 mins
    });

    if (activeIncident) {
      // Incident already reported, just update
      activeIncident.lastSeen = new Date();
      await activeIncident.save();
      console.log(`Updated existing incident: ${activeIncident._id}`);
    } else {
      // New incident, create everything
      await createJiraTicket({ domain });
      await pageOnCall({ domain });
      // ... etc
    }
  }
}

パターン8:失敗したwebhookの再試行#

webhookレシーバーがダウンしている場合、Nova Uptimeは再試行する必要があります。

Nova Uptimeの設定:

  1. ドメイン設定 → Webhooks
  2. webhookをクリック
  3. 詳細設定 → Retry Policy
  4. 有効化:「Retry on failure」
  5. 最大再試行回数:3
  6. 再試行間隔:指数バックオフ(5秒、10秒、20秒)

webhookレシーバーは冪等(複数回呼び出しても安全)である必要があります:

// Good: Idempotent
async function handleIncident({ domain, status, eventId }) {
  // Check if already processed
  const processed = await ProcessedEvents.findOne({ eventId });
  if (processed) {
    return res.json({ success: true, cached: true });
  }

  // Process incident
  await doActualWork();

  // Record as processed
  await ProcessedEvents.create({ eventId, processedAt: new Date() });

  res.json({ success: true });
}

webhook integrationの実例#

Integration 1:Zapier#

カスタムwebhookを構築したくない場合は、Zapierを利用できます:

  1. Nova Uptime → Zapier → Slack/Jira/メールなど
  2. コーディング不要
  3. 制約:制御性が低く、レイテンシが増加

Integration 2:GitHub Actions#

インシデント発生時にGitHub Action(オートスケーリング、ロールバックなど)をトリガーします:

async function handleIncident({ domain, status }) {
  if (status === 'down') {
    // Trigger GitHub Actions workflow
    await triggerGitHubAction({
      repo: 'mycompany/infrastructure',
      workflow: 'incident-response.yml',
      inputs: {
        domain,
        action: 'scale-up'
      }
    });
  }
}

Integration 3:AWS Lambda#

サーバーレスでwebhookを処理する場合はLambdaを使います:

# AWS Lambda function
import json
import boto3

def lambda_handler(event, context):
    body = json.loads(event['body'])
    domain = body['domain']
    status = body['status']

    if status == 'down':
        # Auto-scale on AWS
        ec2 = boto3.client('ec2')
        ec2.start_instances(InstanceIds=['i-1234567890abcdef0'])

    return {
        'statusCode': 200,
        'body': json.dumps({'success': True})
    }

webhookのセキュリティ#

webhook署名を検証する#

Nova UptimeはすべてのwebhookをHMAC-SHA256で署名します。処理前に検証してください:

const crypto = require('crypto');

app.post('/webhooks/uptime-incident', (req, res) => {
  const signature = req.headers['x-gum-signature'];
  const body = JSON.stringify(req.body);
  const secret = process.env.NOVAUPTIME_WEBHOOK_SECRET;

  // Compute expected signature
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body)
    .digest('hex');

  if (signature !== expected) {
    console.error('Invalid webhook signature');
    return res.status(401).json({ error: 'Unauthorized' });
  }

  // Process webhook
  handleIncident(req.body);
  res.json({ success: true });
});

レート制限

webhookレシーバーは呼び出しをレート制限する必要があります:

const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 100 // max 100 requests per minute
});

app.post('/webhooks/uptime-incident', limiter, (req, res) => {
  // Handle webhook
});

タイムアウトの処理

webhookレシーバーは素早く応答する必要があります:

app.post('/webhooks/uptime-incident', async (req, res) => {
  // Respond immediately
  res.json({ success: true });

  // Do real work in background
  setTimeout(async () => {
    await handleIncident(req.body);
  }, 0);
});

webhookのテスト方法#

テスト方法1:ngrokによるローカルテスト#

  1. ローカルのwebhookレシーバーをlocalhost:3000で起動
  2. ngrokを実行:ngrok http 3000
  3. 公開URLを取得:https://abc123.ngrok.io
  4. Nova Uptimeで設定:https://abc123.ngrok.io/webhooks/uptime-incident
  5. Nova Uptimeで「Test」をクリック → ローカルコンソールでリクエストを確認

テスト方法2:Webhook Tester#

無料テストにはwebhook.siteを利用できます:

  1. webhook.siteにアクセス
  2. ユニークURLをコピー
  3. Nova Uptimeでwebhookレシーバーとして設定
  4. テスト → webhook.siteのダッシュボードでリクエストを確認

webhookの監視#

webhookの健全性を追跡します:

async function monitorWebhookHealth() {
  const stats = await WebhookEvent.aggregate([
    {
      $group: {
        _id: null,
        totalEvents: { $sum: 1 },
        successCount: { $sum: { $cond: ['$success', 1, 0] } },
        failureCount: { $sum: { $cond: ['$success', 0, 1] } },
        avgResponseTime: { $avg: '$responseTime' }
      }
    }
  ]);

  const successRate = stats[0].successCount / stats[0].totalEvents;

  if (successRate < 0.95) {
    // Alert: Webhook success rate below 95%
    await alertSlack(`
      Webhook health: ${(successRate * 100).toFixed(1)}% success rate
      Failed events: ${stats[0].failureCount}
    `);
  }
}

まとめ:webhook integrationチェックリスト#

  • ✅ webhookレシーバーのエンドポイントを構築
  • ✅ Nova Uptimeの設定でwebhookを構成
  • ✅ サンプルデータでwebhookをテスト
  • ✅ webhook署名を検証(HMAC-SHA256)
  • ✅ 再試行ロジックと冪等性を実装
  • ✅ webhookエンドポイントにレート制限を追加
  • ✅ 応答タイムアウトの処理を設定
  • ✅ インシデントワークフローを構築(Jira + ステータスページ + Slack)
  • ✅ 実際のインシデントまたは強制的な障害でテスト
  • ✅ webhookの健全性と成功率を監視
  • ✅ チーム向けにwebhookエンドポイントをドキュメント化

今すぐ始める

webhookを使えば、モニタリングはアラートのみの仕組みから、完全自動化されたインシデント対応へと進化します。

Nova Uptimeをご利用の場合は、ドメイン設定にアクセスして最初のwebhookを追加してください。まずはシンプルに、インシデントをデータベースに記録するだけから始めましょう。その後、integrationを1つずつ追加していけば大丈夫です。

webhookドキュメント:Nova Uptime APIドキュメント

Monitor Your Website Before It Goes Down

Get uptime monitoring, SSL tracking, domain expiry alerts, and email health checks. Free plan — no credit card required.

Start Monitoring Free

関連記事