# 固定 IP で Webhook を送る方法：NAT ゲートウェイ・プロキシ・中継サーバーと費用

> 取引先が送信元 IP で受信を制限しているときに Webhook を固定の IP から送る方法として、NAT ゲートウェイ・フォワードプロキシ・中継サーバーの構成と月額の目安、署名と併用する理由を説明します。

公開日: 2026-09-27
Source: https://webhookadmin.com/ja/blog/webhook-static-ip/

## 要点

- 送信元の IP を固定する方法は、NAT ゲートウェイ・フォワードプロキシ・中継サーバーの 3 つです。AWS の東京で NAT ゲートウェイを 2 つ置くと、通信量を除いて月 約 98 USD です。
- 固定 IP のサーバーは取引先に信頼される送信元になるので、送る直前の名前解決の検査とリダイレクトを追わない設定（SSRF 対策）を必ず入れます。
- IP の許可は経路を絞るだけなので、受け側には署名の検証も併用してもらいます。送信元 IP は秘密ではなく、公開して構いません。

取引先に Webhook を送ろうとしたら「送信元の IP アドレスを教えてください。ファイアウォールで許可します」と言われることがあります。クラウドやサーバーレスで動くアプリは、送信元の IP がデプロイやスケールのたびに変わるので、そのままでは答えられません。この記事では、送信元を固定する 3 つの構成と費用、そして固定 IP と署名をどう組み合わせるかを書きます。

## よくある場面

cybozu developer community に、2026 年 4 月にこんな質問が投稿されています（[WebhookでのKintone外部連携時のIPアドレス](https://community.cybozu.dev/t/topic/12534)）。kintone から Chatwork へ Webhook で連携しようとしたら、会社の IP 制限のポリシーで「通知を送るシステム側の固定 IP アドレスの情報が必要」と言われた、というものです。回答では、cybozu.com の IP アドレスは範囲で公開されているが、範囲指定なので受け側によっては難しい、として「中継サーバーを挟むしか方法はないような気がします」と答えられています。

送る側が SaaS の場合も同じです。SendGrid・Backlog・New Relic などは、送信元 IP についての FAQ やお知らせを出しています。KOMOJU のドキュメントは送信元の IP を 8 つ載せたうえで、予告なく変わることがあるので IP での制限は勧めず、署名で検証するよう書いています（[KOMOJU](https://ja.doc.komoju.com/docs/webhooks)）。一方 Stripe は Webhook の送信元 IP を 15 個公開し、変更は 7 日前にメーリングリストで知らせるとしています（[Stripe](https://docs.stripe.com/ips)）。

受信を IP で絞ることが社内の決まりになっている会社では、送る側が「署名があるので IP 制限は要りません」と伝えても通らないことがあります。送る側で固定の IP を用意できれば、この調整は要りません。

## 構成 1：NAT ゲートウェイ

アプリを VPC のプライベートサブネットに置き、外向きの通信を NAT ゲートウェイ経由にします。NAT ゲートウェイに固定の IP（AWS なら Elastic IP）を付ければ、外から見た送信元はその IP になります。

AWS の東京リージョン（ap-northeast-1）の料金は、2026-09-27 に AWS の料金表（Price List API）で確かめた値で次のとおりです。

| 項目 | 単価 | 月額（730 時間） |
|---|---|---|
| NAT ゲートウェイ | 0.062 USD / 時間 | 約 45.3 USD |
| NAT ゲートウェイのデータ処理 | 0.062 USD / GB | 通信量による |
| パブリック IPv4 アドレス | 0.005 USD / 時間 | 約 3.7 USD |

冗長化のために NAT ゲートウェイを 2 つ置き、IP も 2 つにすると、通信量を除いて月 約 98 USD です。これにデータ転送の料金が加わります。

向いているのは、送信の処理がすでに AWS の VPC の中で動いている場合です。Vercel や Cloudflare Workers のように VPC の外で動くアプリからは、この構成は使えません。

出典: [Amazon VPC の料金](https://aws.amazon.com/vpc/pricing/)、AWS Price List API（ap-northeast-1、2026-09-01 発効の単価）

## 構成 2：フォワードプロキシ

固定 IP を持つサーバーにフォワードプロキシ（HTTP CONNECT）を立て、Webhook の送信だけをそこ経由にします。アプリ側は、送信の HTTP クライアントにプロキシを設定するだけです。

```ts
import { ProxyAgent, fetch } from 'undici';

const proxy = new ProxyAgent(process.env.WEBHOOK_PROXY_URL!); // 例: http://user:pass@proxy.internal:4750

await fetch(endpointUrl, {
  method: 'POST',
  headers,
  body,
  dispatcher: proxy,
  redirect: 'manual',
  signal: AbortSignal.timeout(15_000),
});
```

プロキシには、Stripe が公開している HTTP CONNECT プロキシの Smokescreen があります。Webhook 配信の OSS の Convoy は、Smokescreen を包んだ mole を使う方法をブログで案内しており、台数を増やすときはプロキシを複数台置いてロードバランサーの後ろに並べる、としています（[Convoy のブログ](https://www.getconvoy.io/blog/configuring-your-outbound-webhook-requests-with-static-ips)）。

費用はサーバー代と固定 IP の代金です。自分で持つものは、プロキシの冗長化、OS とプロキシの更新、そして後で書く SSRF の対策です。

## 構成 3：中継サーバー

アプリから中継サーバーへ「この URL にこのペイロードを送って」と依頼し、中継サーバーが固定 IP から送って結果を返す構成です。フォワードプロキシとの違いは、中継サーバーが送信の中身を知っていることです。宛先の検査、タイムアウト、応答の記録を中継サーバー側で決められます。

Fly.io はアプリ単位の固定の送信元 IP を持てます。`fly ips allocate-egress --app <アプリ名> -r nrt` で東京（nrt）に IPv4 と IPv6 の組が割り当てられ、IPv4 は 1 つ月 3.60 USD です（[Fly.io のドキュメント](https://docs.fly.io/networking/egress-ips/)）。マシンを作り直しても IP は変わりません。

中継サーバーの例です。アプリとの間は共有の鍵の HMAC で認証し、古い依頼は断ります。

```ts
import { createHmac, timingSafeEqual } from 'node:crypto';
import http from 'node:http';

const SECRET = process.env.SHARED_SECRET!;

http.createServer(async (req, res) => {
  const ts = String(req.headers['x-request-timestamp'] ?? '');
  const sig = String(req.headers['x-request-signature'] ?? '');
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.writeHead(401).end();

  const chunks: Buffer[] = [];
  for await (const c of req) chunks.push(c as Buffer);
  const raw = Buffer.concat(chunks).toString('utf8');

  const expected = createHmac('sha256', SECRET).update(`${ts}.${raw}`).digest('base64');
  if (sig.length !== expected.length || !timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.writeHead(401).end();
  }

  const { url, headers, body } = JSON.parse(raw);
  // ここで宛先を検査してから送る（次の節）
  const r = await fetch(url, { method: 'POST', headers, body, redirect: 'manual', signal: AbortSignal.timeout(15_000) });
  res.writeHead(200, { 'content-type': 'application/json' }).end(JSON.stringify({ status: r.status }));
}).listen(8080);
```

## 固定 IP の送信で必ず入れる SSRF の対策

固定 IP のサーバーは、取引先のファイアウォールに「信頼できる送信元」として登録されます。同時に、送信先の URL は利用者が登録するものです。ここに社内のアドレスを指す URL を登録されると、固定 IP のサーバーが社内のサービスへリクエストを送ってしまいます。freee が Webhook を開発したときの記事でも、利用者が入れた URL から社内の API を叩かれないかが一番の論点になっています（[freee Developers Hub](https://developers.freee.co.jp/entry/webhook-development-was-hard)）。

入れておく検査は次のとおりです。詳しい手順とコードは [SSRF 対策の記事](https://webhookadmin.com/ja/blog/webhook-ssrf-protection/) にあります。

- 登録のときに、https だけ・ポートは 443 などに限る・IP を直接書いた URL と `.internal` などの社内向けの名前を断る。
- 送る直前に名前を引き、返ってきたアドレスが 1 つでもプライベート・ループバック・リンクローカル（クラウドのメタデータを含む）などに当たれば送らない。
- 検査を通った IP に直接つなぐ（名前を引き直すと DNS リバインディングで検査をすり抜けられる）。
- リダイレクトを追わない。

SkyWay の Webhook の記事も、名前解決で得た IP アドレスを直接使って送る形で SSRF を防いでいます（[NTT ドコモビジネス Engineers' Blog](https://engineers.ntt.com/entry/202512-skyway-webhook/entry)）。

## 署名と併用する理由

IP の許可は「どの経路から来たか」を絞るもので、「誰が送ったか」「途中で書き換えられていないか」までは確かめません。共有のプロキシや NAT の IP は、同じサービスを使うほかの利用者も使っています。受け側は IP で絞ったうえで、署名で送り主と本文を検証するのが確実です。Stripe のドキュメントも、IP の許可リストと署名の確認の両方を使うよう書いています（[Stripe](https://docs.stripe.com/webhooks)）。

取引先には、IP と一緒に署名の検証方法を渡します。[Standard Webhooks](https://www.standardwebhooks.com/) の形式で署名していれば、各言語のライブラリで検証できます。

## IP を公開してよい理由

送信元の IP アドレスは秘密の情報ではありません。HTTPS のリクエストは TCP の接続を往復で確立してから送るので、他人が送信元の IP を偽って最後まで届けることは現実的にできません。IP を知られても、その IP から来たように見せかけて受け側に届けることはできません。Stripe が Webhook の送信元 IP を一覧で公開しているのもそのためです。

公開するときは次の点を決めておきます。

- **一覧の置き場所**: ドキュメントと管理画面の両方に載せる。機械で読める JSON もあると、取引先がファイアウォールの設定を自動で更新できる。
- **変更の知らせ方**: Stripe は 7 日前にメーリングリストで知らせています。
- **2 つ以上の IP**: 1 台の障害で送れなくならないように。取引先には最初から全部を許可してもらう。

## Webhook Admin での扱い

Webhook Admin では、送信先ごとに「固定 IP から送る」を選べます。Starter プラン（月 3,000 円）から使えます。

- 固定 IP の送信元は `209.71.107.233` の 1 つです。受け側ではこの IP を許可します。アドレスは管理画面とドキュメントにも載せています。
- 送る直前に名前を引いた IP をすべて検査し、社内向けのアドレスが 1 つでもあれば送りません。リダイレクトは追いません。送信元が IPv4 なので、送信先には IPv4 のアドレス（A レコード）が要ります。
- 署名（Standard Webhooks）と再送、失敗の記録は、固定 IP の送信でも同じです。送信の記録には、固定 IP から送ったかどうかと送信元の IP が残ります。

API で送信先を作るときは `fixed_ip` を付けます。

```bash
curl -X POST https://api.webhookadmin.com/v1/endpoints \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"consumer_id":"con_...","url":"https://partner.example.jp/webhooks","fixed_ip":true}'
```

## 構成の選び方

| 構成 | 月額の目安 | 向いている場合 |
|---|---|---|
| NAT ゲートウェイ（AWS 東京、2 ゾーン） | 約 98 USD＋通信量 | 送信の処理がすでに VPC の中にある |
| フォワードプロキシ（自前） | サーバー代＋IP 代 | 既存の HTTP クライアントにプロキシを足すだけで済ませたい |
| 中継サーバー（Fly.io など） | IPv4 1 つ 3.60 USD＋マシン代 | サーバーレスから送る、宛先の検査や記録も中継で持ちたい |
| 配信サービスの固定 IP | 各サービスの料金による | 冗長化と SSRF の対策も含めて任せたい |

取引先の IP 制限のために中継サーバーを作って保守する代わりに、Webhook Admin なら Starter プラン（月 3,000 円）から固定の送信元 IP を使えます。[https://app.webhookadmin.com/signup](https://app.webhookadmin.com/signup)

## よくある質問

### サーバーレスのアプリから固定 IP で送るにはどうしますか。

VPC の外で動くアプリには NAT ゲートウェイを付けられないので、固定 IP を持つフォワードプロキシか中継サーバーを経由して送ります。Fly.io のように固定の送信元 IP を割り当てられる基盤に中継を置く方法もあります。

### 固定 IP があれば署名の検証は要りませんか。

署名の検証も要ります。IP の許可は経路を絞るだけで、送り主や改ざんの有無は確かめません。共有のプロキシや NAT の IP はほかの利用者も使うので、IP の許可と署名の検証を併用します。

### Webhook Admin の送信元 IP は何ですか。

209.71.107.233 の 1 つです。Starter プランから、送信先ごとに fixed_ip をオンにするとこの IP から送ります。受け側ではこの IP を許可します。
