通知
対応が必要なことが起きると、Zenavo はチームにメールを送るので、コンソールを開きっぱなしにしなくて済みます。同じアラートを Slack、Discord、Telegram、自分の Webhook に送ることもできます。
イベント
| イベント | 送られるとき |
|---|---|
| Deployment failed | デプロイかロールバックが完了しなかった。メールには、サービスのビルド中に失敗したのか展開中に失敗したのかが書かれます。 |
| Server setup failed | サーバーのセットアップか再インストールが終わらなかった。メールには理由と、再試行のために SSH の認証情報をいつまで保持するかが書かれます。 |
| Service suspended | サービスがクラッシュ上限を超えて再起動し、停止された。 |
| Server offline | サーバーが 3 回続けて状態確認に応答しなかった(約 3 分)。応答が戻ると 2 通目のメールが届きます。 |
| Disk or memory almost full | サーバーのディスクが 90% を超えたか、メモリが 3 回続けて 90% を超えた。使用率が 85% を下回ると再びアラートが出せるようになります。 |
| New SSH login source | ある IP アドレスがチームのサーバーに初めて SSH でログインした。新しいネットワークから接続した直後なら想定どおりですが、そうでなければ警告のサインです。 |
| Usage limit | チームのイメージ転送が請求期間の許容量の 80% または 100% に達した。100% になるとサーバーは新しいイメージを pull できなくなります。 |
同じプロジェクト、サービス、サーバーについて、各アラートは 1 時間に 1 回までです。1〜2 回の一時的な応答なしでは何も送られません。
自分のアカウントに関するセキュリティメール(新しいデバイスからのサインイン、承認した CLI のサインイン、新しい API キー)についてはセキュリティを参照してください。本人にだけ届き、どのロールでもデフォルトでオンで、Notifications ページの Security に表示されます。
誰に届くか
メールは、プロジェクトやサーバーを所有するチームのメンバーに届きます。
- オーナーと管理者は、オフにしない限りすべてのイベントを受け取ります。
- メンバーは、イベントをオンにするまで何も受け取りません。
- Viewer は通知を受け取りません。
受け取るイベントは Account settings → Notifications で選びます。設定はアカウント単位で、所属するすべてのチームに適用されます。
メールの内容
プロジェクト、サービス、サーバーの名前、日時(UTC)、コンソールでの該当ページへのリンク。メールには変数の値、シークレット、コマンド、ログの本文は含まれません。ログはコンソールで確認してください。
チャンネル
チームの管理者は、チームの通知をチャットアプリや Webhook にも送れます:Account settings → Notifications → Team channels(サイドバーで選んだチームが対象)。チャンネルごとにイベントを選べ、上記に加えて Deployment succeeded(メールでは送られません)も受け取れます。チャンネルにはメールと同じアラートが同じ 1 時間 1 回の制限で届き、誰のメール設定にも左右されません。
| チャンネル | 必要なもの |
|---|---|
| Slack | チャンネルの Incoming Webhook の URL(https://hooks.slack.com/services/…)。 |
| Discord | チャンネルの Webhook:チャンネル設定 → 連携サービス → ウェブフック(https://discord.com/api/webhooks/…)。 |
| Telegram | @BotFather で得たボットのトークンと、チャット ID(-1001234567890 のような数値か、公開チャンネルの @username)。先にボットをチャットに追加してください。 |
| Webhook | 任意の https:// URL。Zenavo は署名付きの JSON を POST します(後述)。 |
Test はすぐにメッセージを送り、届いたかどうかを表示します。各チャンネルには最後の配信結果か失敗理由が表示され、失敗した配信は約 13 分の間に 3 回再試行されます。チームあたり最大 20 チャンネルです。
Webhook の URL とボットのトークンはシークレットです。暗号化して保存され、コンソールにはホストかチャットしか表示されません。Zenavo はアドレスがすべてパブリックなホストにだけ送信し、リダイレクトには従いません。
Webhook のペイロード
{
"type": "deploy_failed",
"team_id": "team_…",
"subject": "Deployment failed: shop",
"text": "The deployment of project \"shop\" failed at 2026-10-19 08:12 UTC.\nIt failed while building service \"web\".\n",
"url": "https://zenavo.app/projects/proj_…/deployments/job_…",
"time": "2026-10-19T08:12:03Z"
}type は deploy_failed、deploy_succeeded、service_suspended、server_offline(サーバーが戻ったときにも送られます)、server_resources、usage_limit、test のいずれかです。2xx の応答なら配信済みとみなします。
各リクエストには X-Zenavo-Event、X-Zenavo-Timestamp(Unix 秒)、X-Zenavo-Signature: v1=<hex> が付きます。最後のものはチャンネルの署名シークレットで <timestamp>.<生のボディ> を HMAC-SHA256 したものです。シークレット(whsec_…)は Webhook の追加時に一度だけ表示され、Edit では再表示されませんが、API で入れ替えられます。署名は生のバイト列に対して検証し、古いタイムスタンプは拒否してください。
import crypto from 'node:crypto'
function verify(rawBody, headers, secret) {
const ts = headers['x-zenavo-timestamp']
const expected = 'v1=' + crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex')
const given = headers['x-zenavo-signature'] ?? ''
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300
const a = Buffer.from(given), b = Buffer.from(expected)
return fresh && a.length === b.length && crypto.timingSafeEqual(a, b)
}