MOOBON
Architecture Note ・ AWS / VPC / fck-nat

NAT Gateway の月額を見直したいECS の固定 IP を維持したまま fck-nat に置き換えた記録

2026年5月9日 公開読了 約 13 分MOOBON 技術ブログ

AWS の王道 NAT Gateway + EIP は機能こそシンプルですが、時間料金 + データ処理料金の二段構造で月額が意外と効いてきます。 MOOBON のあるシステムでは半年平均で 月 $109 を NAT Gateway に支払っていました。

とはいえ、SaaS の IP ホワイトリスト要件などで外向き IP を固定する必要があると NAT 装置を捨てられない。 本記事は当社が 固定 IP の要件は満たしたまま、NAT Gateway を fck-nat に置き換えた記録です。 料金構造の検証から、Launch Template / IAM ポリシー / systemd ユニットといった一次情報レベルの設計まで開示します。

NAT Gateway の機能と料金構造

NAT Gateway は AWS のマネージドな NAT 装置で、Public Subnet に置いて EIP を 1 本紐付けると、Private Subnet からインターネット向けの outbound 通信を その EIP を送信元 IP として外に出す役割を果たします。可用性は AWS 持ちで、SLA は実質マネージド水準。設定は軽く、AZ ごとに 1 本立てれば AZ 障害にも追従できる ── 機能面では文句なしの王道です。

一方、料金は二段構造になっており、運用していると月額がじわじわ積み上がっていきます。

単価(2026 年 5 月時点 / Tokyo)

料金項目NAT Gateway(1 本)
時間料金$0.062/h ≒ 月 $45
データ処理料金(NAT 通過分)$0.062/GB
EIP(1 本・Public IPv4 課金)$0.005/h ≒ 月 $3.65
小計(時間 + EIP、転送量除く)月 $48+

ポイントは 「時間料金($0.062/h)」と「データ処理料金($0.062/GB)」が両方乗る点です。時間料金だけなら月 $45 で済みますが、ECS 等のシステムから流れる転送量に応じて、データ処理料金が比例的に上乗せされていきます。マルチ AZ 構成だと AZ 数 × 月 $45+ がそのままベタ乗りする、という構造もよく問題になります。

※ 価格は AWS 公式の公開料金(Tokyo / 2026 年 5 月時点)に基づく概算で、為替・改定で変動します。最新値は AWS 公式の料金ページでご確認ください。

MOOBON 実費でみる NAT Gateway の月額

§1 で見た単価が、当社で実際にどう積み上がっていたかを Cost Explorer で確認しました。本記事の対象 VPC を持つ AWS アカウント単独に絞り、APN1-NatGateway-Hours(時間料金)と APN1-NatGateway-Bytes(データ処理料金)を抽出した数字です。

時間料金データ処理料金合計
2025-10$46.13$65.92$112.05
2025-11$44.64$62.27$106.91
2025-12$46.13$62.14$108.27
2026-01$46.13$62.90$109.03
2026-02$41.66$66.44$108.10
2026-03$45.20$66.13$111.33
2026-04(fck-nat 移行後)$0$0$0

半年平均で 月 $109(時間 $45 + データ処理 $64)、ここで意外なのが データ処理料金の方が時間料金より大きかったことです。「NAT Gateway は時間課金がメイン」という何となくの感覚に反して、実費では転送量側の方が大きく効いていました。

何が NAT を通っていたのか

月 $64 を作っていた NAT 通過 1,004 GB の内訳を、Cost Explorer の他の USAGE_TYPE と組み合わせて見ると、おおよそ次の比率になっていました。

  • AWS 内部 API 向け 約 650 GB(全体の約 65%、料金にして約 $40) ─ CloudWatch Logs(awslogs)、Secrets Manager、SSM Parameter Store、ECR メタデータ API など Interface Endpoint なしのサービスへの通信。APN1-DataTransfer-Out-Bytes(外部インターネット課金)としては計上されないが、NAT Gateway は通るためデータ処理料金は乗る
  • 外部 SaaS / API 向け 約 354 GB(全体の約 35%、料金にして約 $22) ─ 本来の用途である IP 固定要件のもとでの外部通信。APN1-DataTransfer-Out-Bytes としても課金される

「Logs 単体でいくら」までは VPC Flow Logs を解析しないと特定できませんが、ECS の awslogs ドライバが平常運転で常時 Logs API に書き込み続ける性質上、AWS 内部 API 分($40)の中で大きな割合を占めるとみています。常時ダラ流しでデータ処理料金が積み上がっていた、というのが実態でした。

S3 Gateway Endpoint は無料・ノーリスク。まだ入れていなければ迷わず入れる
S3 Gateway Endpoint は 追加料金なし・既存通信への悪影響なしで VPC に追加でき、ECR レイヤ Pull など S3 経由の通信が NAT を通らなくなります。NAT データ処理料金の中で容量が大きい部分を即座に削れるため、VPC にまだ入っていなければ、fck-nat の検討より先に必ず入れるべき施策です。

それでも NAT Gateway を使う理由 ─ ECS の固定 IP 要件

ここまでで NAT Gateway がそれなりに高いことを見ました。では、なぜ ECS で NAT 装置を捨てられないのか? 多くの場合、答えは 「外向き IP を固定したい」要件にあります。

ECS(Fargate / EC2)で動くアプリから外部 API を叩くとき、「アクセス元 IP を固定してください」と先方から要求されることがあります。決済代行・与信系の SaaS、データ連携系の API、社外システムの許可リストなど、業界によっては当たり前の前提条件です。「outbound IP を固定したい」という要望は、現場でだいたい次の 3 パターンに収斂します。

1. 接続先 SaaS / API の IP ホワイトリスト方式

一番多いのがこのパターン。決済代行事業者・与信系 SaaS・データ連携 API などで、「接続元 IP を事前申請してホワイトリストに登録する」方式が運用ルールになっているケース。当社で実際に NAT 経由にしている接続先も、ほとんどがこの方式です。

  • 申請後の IP 変更には先方の作業が伴うため、IP は「めったに変えない前提」で運用される
  • ECS の動的 IP のままでは出口でマッピングする必要があり、結局なんらかの NAT 装置が要る
  • 固定する IP の数は 1 本で十分なことが多い(冗長化しても 2 本)

2. 接続元監査・コンプライアンス要件

金融・医療・公共系のシステムでよくある要件で、監査ログに残る送信元 IP を「自社管理の固定 IP」にそろえておきたいケース。アクセスログだけでなく、SSL/TLS の Client Hello の SNI と組み合わせて「どのシステムが、どの相手と通信したか」を後から追跡可能にする目的です。

この要件では、IP の本数より 「IP の所有関係が明確であること」(Whois / RIR 上で自社配下と辿れること)が重視されることもあり、AWS の EIP を利用する場合は EIP の IP の Whois が AWS 名義であることに留意が必要です。Whois 上で自社名義が必要な場合は BYOIP まで踏み込むことになります。

3. 取引先の社内 NW 許可リストへの登録

取引先の VPN や社内 NW、専用線越しのオンプレ DB に接続するケース。先方の Firewall / NACL に 「許可する送信元 IP」として登録してもらう運用です。1 と似ていますが、決定的に違うのは 「IP 登録までの社内手続きに時間がかかる」点で、IP 変更がより重い行為になりがちです。

ここで決めておきたい 3 つ
  1. 固定したい IP の本数(1 / 2 / それ以上)── 冗長性の必要度が決まる
  2. 許容できるダウンタイム(数分の瞬断 OK か / 1 秒も止まれない要件か)── アーキテクチャの選択肢が決まる
  3. IP 変更時の社外調整コスト(自社内で完結 / 申請が必要 / 数週間かかる)── 後述の自動 EIP 付け替えを採用するかが決まる

コスト削減と固定 IP を両立する選択肢

NAT Gateway の月額(§1, §2)と、それでも NAT 装置が必要な理由(§3)を踏まえると、論点は 「コスト削減と固定 IP の両立をどう取るか」 に絞られます。現実的な候補としては NAT Gateway か EC2 NAT(fck-nat / AlterNAT)が中心で、本記事ではこの 2 系統を前提に進めます。

EC2 NAT(自前 / fck-nat / AlterNAT 系)

1 台の EC2 を「NAT 装置」として動かし、Public Subnet に置いて EIP を貼り、Private Subnet のルートテーブルで 0.0.0.0/0 → その ENI に向ける構成。これを 「設定済み AMI として配布」しているのが fck-nat、これに 「自前 NAT をプライマリで動かし、障害時に NAT Gateway へフェイルオーバー」のパターンを加えたのが AlterNAT 系のアプローチです(平常時は安価な自前 NAT で動かし、障害時のみ高価な NAT Gateway に切り替えるため、コスト削減と SLA 担保を両取りできる設計)。

  • 強み: 月額の固定費が NAT Gateway 比で大きく下がる(後述)。EIP 1 本で IP 固定もできる
  • 弱み: 単一インスタンス構成だと、可用性はそのインスタンス次第。本格 HA を作ると複雑度が上がる(§8 で詳述)
  • IP 固定の容易さ: ◎ EIP を ASG に自動アタッチさせる仕組みは AMI が標準で持っている

比較表(2026 年 5 月時点 / Tokyo / 1 本あたり)

選択肢IP 固定可用性設定の重さ月額感
NAT Gateway + EIP$48+ + 転送量課金
fck-nat(EC2)(単一 AZ なら単一インスタンス)$14〜$18

fck-nat なら送信元 IP の固定とコスト削減を両立できる

fck-nat の本質は 「EIP を 1 本貼った EC2 ベースの NAT 装置」です。これは outbound IP の固定要件 を NAT Gateway と同等に満たしつつ、副産物として NAT Gateway 比のコスト圧縮も同時に得られる選択肢になります。

Before / After

$109(NAT Gateway)→ 月 約 $11(fck-nat)で、月 -$98(1 USD = 150 円換算で 約 -¥14,700)の削減

コスト最適化の全体像は姉妹記事の AWS の “見えない固定費” 月 $310 を見つけて回収するまで に整理しています。

金額だけで判断しないでください。 fck-nat の安さは「マネージドサービスを 1 段降りた」結果であり、後述の可用性・運用責任を引き取ることとセットです。コストと運用負荷のどちらを取るか・どこで折り合いをつけるかは、システム単位で判断する必要があります。

fck-nat とは何か ─ 仕組みと「fck」の意味

名前の由来 ─ feasible cost konfigurable

名前を見たときに「やべぇ NAT」を連想したくなるところですが、公式ドキュメントの説明は feasible cost konfigurable NAT の頭文字です(configurable ではなく konfigurable と綴られているのが頭文字を揃えるための言葉遊び)。「現実的なコストで、設定可能な NAT」という意図が込められています。

実体は「設定済みの EC2 AMI」

fck-nat の実体は Amazon Linux 2023 ベースの EC2 AMIで、起動した時点で次の設定が入っています。

  • net.ipv4.ip_forward = 1(Linux カーネルの IP フォワーディング有効化)
  • iptables -t nat -A POSTROUTING -o ens5 -j MASQUERADE(送信元 IP を NAT 装置の IP に書き換える)
  • EIP を自動で AssociateAddress する fck-nat.service
  • (オプション)CloudWatch Agent によるメトリクス送信

つまり、「Linux カーネルにもとから備わっている NAT 機能を、AMI として配布可能な形に組み立て直したもの」です。特殊なソフトウェアが入っているわけではなく、iptables と sysctl の世界の話に閉じます。

補足: fck-nat.serviceinactive なのは仕様
起動後に systemctl is-active fck-nat を打つと inactive が返ってきます。これは Type=oneshot / RemainAfterExit=no で書かれた systemd ユニットで、「起動時に EIP のアタッチと iptables の設定を済ませて exit する」設計のためです。NAT 機能そのものはカーネルが担保しているため、サービスが exit していても通信は継続します(実環境で 2 週間以上 inactive のまま 60MB 以上の通信を MASQUERADE してきた実績があります)。

AMI の配布形態と料金

fck-nat の AMI は AWS Marketplace ではなく、AMI 配布専用アカウント 568608671756 から各 AWS アカウントが直接参照する形で公開されています。AMI 自体は無償で、課金されるのは AMI を起動した EC2 インスタンス料金と EBS 料金のみです。

  • ARM 系: t4g.nano 等の Graviton インスタンスに対応(公式の最安推奨はこれ)
  • x86_64 系: t3 / t3a / t2 ファミリ向け AMI もあわせて公開
  • 2026 年 1 月リリースの v1.4.0(当社で採用したバージョン)で AL2023 ベースに統一

なお当社は 余剰の Reserved Instance を活用するため、x86_64 系の t3a.micro を選択しています(新規導入なら最安推奨の ARM t4g.nano が合理的です。経緯の詳細は §6-5 AMI 選定 に書きました)。

なぜ fck-nat が必要だったか

AWS 公式の NAT instance AMI(Amazon Linux 1 ベースの amzn-ami-vpc-nat-*)は AL1 EOL 後に事実上メンテナンスされておらず、現在の公式推奨は NAT Gateway 一択 ── つまり「自前 NAT」のオプションは公式ロードマップから外れた状態にあります。fck-nat はその穴を OSS コミュニティが埋めたもので、「設定済みの AMI」と「EIP の自動アタッチ」の 2 点を切り出して AMI 化した、というシンプルな本質です。

設定方法 ─ MOOBON で採用した実構成

ここからは MOOBON が実際に運用している fck-nat 環境を、ネットワーク・IAM・Launch Template / UserData・ASG まで具体的に開示します。リソース ID やプロジェクトタグ等の固有情報は伏せていますが、構造そのものはそのままです。

6-1. 構成図と全体像

対象 VPC のリソースマップを下に示します。Public Subnet 3 つ(10.0.0.0/24 / 10.0.1.0/24 / 10.0.2.0/24)、Private Subnet 2 つ(10.0.10.0/24 / 10.0.11.0/24)、Route Table 2 本(route-internet-gateway / route-moobon-private)、IGW 1 本、S3 Gateway Endpoint がある構成です。fck-nat インスタンスは moobon-public-10.0.0.0/24(AZ ap-northeast-1a)に配置し、Private Subnet からの 0.0.0.0/0 ルートを fck-nat の ENI に向けています。

VPC リソースマップ。Public Subnet 3 つと Private Subnet 2 つ、Route Table 2 本、IGW、S3 Gateway Endpoint を含む moobon-main-vpc の全体構成
図 1: 対象 VPC のリソースマップ。Public Subnet と Private Subnet、Route Table、ネットワーク接続(IGW / VPC Endpoint)が一望できる。fck-nat は moobon-public-10.0.0.0/24(AZ-1a)に配置している。

6-2. ネットワーク設計(VPC / Subnet / Route Table)

ECS インスタンス(10.0.11.0/24 など Private Subnet 配置)の デフォルトルート 0.0.0.0/0 を、共通の Private Route Table から fck-nat の ENI に向けます。fck-nat 側はインスタンス起動時に aws ec2 replace-route を叩いて自分の ENI を Route Table に設定するため、新しいインスタンスが起動した瞬間に経路が更新されるのがポイントです。

VPC: moobon-main-vpc (10.0.0.0/16) ├── Public Subnets │   ├── moobon-public-10.0.0.0/24  (ap-northeast-1a)  ← fck-nat 配置 │   ├── moobon-public-10.0.1.0/24  (ap-northeast-1c) │   └── moobon-public-10.0.2.0/24  (ap-northeast-1d) │       └── Route Table: route-internet-gateway │           0.0.0.0/0 → IGW └── Private Subnets ├── moobon-private-10.0.10.0/24 (ap-northeast-1d) └── moobon-private-10.0.11.0/24 (ap-northeast-1a)  ← ECS インスタンス配置 └── Route Table: route-moobon-private 0.0.0.0/0 → fck-nat ENI(動的に置換)

6-3. EIP の確保と自動アタッチ

outbound IP として固定したい EIP を 1 本確保し、その allocation ID を fck-nat の /etc/fck-nat.conf に書きます。fck-nat.service が起動時にこの conf を読み、AssociateAddress で自分にアタッチする動作です。ASG が新しいインスタンスを起動するたびに、同じ EIP が新インスタンスに自動で付け替わるので、SaaS 側のホワイトリストに登録した IP は固定のまま運用できます。

# /etc/fck-nat.conf(マスク版) eip_id=eipalloc-XXXXXXXXXXXXXXXXX cwagent_enabled=true

※ EIP は常に fck-nat インスタンスにアタッチされた状態で運用されるため、未アタッチ時に発生する「EIP 遊休課金」は本構成では発生しません。発生するのは Public IPv4 課金($0.005/h ≒ 月 $3.65、§1 単価表参照)のみです。

6-4. IAM ポリシー(fck-nat 運用で必要な EC2 系権限)

fck-nat の運用に必要な IAM ポリシーは下記です。Managed の AmazonSSMManagedInstanceCore(SSM Session 用)に加えて、Inline ポリシーで EC2 系 API を絞り込んでいます。「最小権限」というには甘く、fck-nat 公式の推奨セットを踏襲しています(実際に cloud-config の runcmd が叩くのは ModifyInstanceAttributeReplaceRoute、fck-nat.service が EIP 操作で AssociateAddress / DisassociateAddress を使い、Describe* 系は状態確認用です)。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:AssociateAddress",
        "ec2:DisassociateAddress",
        "ec2:ModifyNetworkInterfaceAttribute",
        "ec2:ModifyInstanceAttribute",
        "ec2:ReplaceRoute",
        "ec2:CreateRoute",
        "ec2:DescribeAddresses",
        "ec2:DescribeInstances",
        "ec2:DescribeNetworkInterfaces",
        "ec2:DescribeRouteTables"
      ],
      "Resource": "*"
    }
  ]
}

Resource: "*" にしているのは、Modify* / Replace* 系の API がリソース ARN ベースの制限と相性が悪いためです。本格的に絞るなら aws:ResourceTag 条件で Project = your-project のタグを持つリソースのみに限定する方法が取れますが、本記事では取り回しを優先しています。

6-5. AMI 選定 ─ 公式推奨は t4g.nano、当社は t3a.micro

fck-nat の公式推奨は最安構成の t4g.nano(ARM / Graviton)で、月 $3 台まで落ちます。当社は t3a.micro(x86_64)を採用しました。理由は単純で、余剰の Reserved Instance を活用するためです。

新規導入なら ARM の t4g.nano を選ぶのが合理的です。当社の構成を真似する場合も、特別な理由がなければ ARM 系を選んでください。なお採用した AMI は本記事執筆時点で次のものです:

AMI ID:   ami-06482499a24c86ab1 AMI 名:   fck-nat-al2023-hvm-1.4.0-20260126-x86_64-ebs ベース:   Amazon Linux 2023 バージョン: v1.4.0(2026 年 1 月リリース) 配布元アカウント: 568608671756

6-6. Launch Template / UserData(現行 v6)

運用中の Launch Template の UserData(cloud-config)全文です。EIP 自動アタッチと、Private Route Table の 0.0.0.0/0 を自分の ENI に書き換える処理を 1 ファイルでこなしています。

#cloud-config
write_files:
  - path: /etc/fck-nat.conf
    content: |
      eip_id=eipalloc-XXXXXXXXXXXXXXXXX
      cwagent_enabled=true
    owner: root:root
    permissions: '0644'
runcmd:
  - systemctl restart fck-nat.service
  - |
    TOKEN=$(curl -sX PUT "http://169.254.169.254/latest/api/token" \
      -H "X-aws-ec2-metadata-token-ttl-seconds: 300")
    INSTANCE_ID=$(curl -sH "X-aws-ec2-metadata-token: $TOKEN" \
      http://169.254.169.254/latest/meta-data/instance-id)
    REGION=$(curl -sH "X-aws-ec2-metadata-token: $TOKEN" \
      http://169.254.169.254/latest/meta-data/placement/region)
    MAC=$(curl -sH "X-aws-ec2-metadata-token: $TOKEN" \
      http://169.254.169.254/latest/meta-data/mac)
    ENI_ID=$(curl -sH "X-aws-ec2-metadata-token: $TOKEN" \
      http://169.254.169.254/latest/meta-data/network/interfaces/macs/$MAC/interface-id)
    aws ec2 modify-instance-attribute --region $REGION \
      --instance-id $INSTANCE_ID --no-source-dest-check
    aws ec2 replace-route --region $REGION \
      --route-table-id rtb-XXXXXXXXXXXXXXXXX \
      --destination-cidr-block 0.0.0.0/0 \
      --network-interface-id $ENI_ID

ポイントは 起動時に走る 2 つの処理です。

  1. modify-instance-attribute --no-source-dest-check:NAT 装置として「自分の IP 宛でないパケットも処理する」ために必須(Source/Destination Check を切る)
  2. replace-route:Private Route Table の 0.0.0.0/0 エントリを新しいインスタンスの ENIに向け直す。ASG 経由で再起動された際の経路自動切り替えを担保

6-7. ASG self-healing(min=max=desired=1)

冗長性を持たない構成のかわりに、ASG の min=max=desired=1 で「インスタンスが 1 つ確実に立っている状態」を維持します。fck-nat インスタンスがクラッシュ等で落ちると、ASG が自動的に同じ Launch Template から新しいインスタンスを起動し、そのインスタンスが UserData の処理で EIP を引き継ぎRoute Table の 0.0.0.0/0 を自分に向け直すので、数分の瞬断はあるが自動復旧します。

実観測:fck-nat の self-healing 復旧時間(2026-05-10 計測)

記事執筆中に意図的に fck-nat インスタンスを terminate し、外向き通信が復旧するまでを計測しました。

  • T0:fck-nat インスタンス terminate
  • T+111 秒:新インスタンスが ASG に立ち上がり、InService / Healthy
  • T+142 秒:UserData の replace-route で Route Table の 0.0.0.0/0 が新 ENI に切り替わり、EIP も新 ENI に再アタッチされて外向き通信が復旧

terminate から外向き通信復旧まで 約 2 分 22 秒。EIP の Public IP は新インスタンスにそのまま引き継がれているため、SaaS 側のホワイトリストには影響しません。

Auto Scaling Group の詳細画面。希望するキャパシティ 1、スケーリング制限 1-1、ステータス At desired capacity、起動テンプレートは v6(runcmd replace-route for reliable automation)、AMI は ami-06482499a24c86ab1、インスタンスタイプは t3a.micro、AZ は ap-northeast-1a 単一構成
図 2: ASG の詳細。希望/最小/最大キャパシティはすべて 1、ステータスは At desired capacity、配置 AZ は単一(ap-northeast-1a)、起動テンプレートは v6 を Latest として参照。

Launch Template ─ 自動起動が確認できるまでの流れ

現在動いている Launch Template は v6 ですが、ASG self-healing の自動起動が安定して動くまでに、同日中で v1 から v6 まで 6 回書き直しています。各バージョンが「何を直そうとしていたか」を残しておくと、似た構成を組む方が同じ罠を避けやすいので、Description ベースで開示します。

Launch Template kabu-homerun-fcknat-lt の 6 バージョンが並んだバージョン履歴。v1 から v6 まで Description と作成時刻が確認できる
図 3: Launch Template バージョン履歴。同日(2026-04-20)の 1 時間 17 分の間に v1 → v6 まで進化している。Description 列に各バージョンの意図が残っている。
VerDescription作成時刻
1(初期作成 / 説明なし)13:50:48
2t3a.micro x86_64 (use unused RI)13:55:28
3cloud-config write_files for automatic EIP attach14:45:12
4write_files + runcmd SDC disable14:50:25
5v5: add route_table_ids_csv for auto route update15:01:15
6v6: runcmd replace-route for reliable automation ← 現行15:07:49

v2 → v3:cloud-config による EIP 自動アタッチ

v2 までは EIP を手動でアタッチしていました。ASG self-healing で再起動された場合、新しいインスタンスに EIP が自動で付かない問題があり、v3 で write_files/etc/fck-nat.confeip_id を埋め込み、起動時に fck-nat.service が読む方式へ移行しました。

v3 → v4:Source/Destination Check の無効化を runcmd に移管

v3 までで EIP は自動アタッチできるようになりましたが、NAT 装置として動くには Source/Destination Check を切る必要があります。これを起動時の cloud-config 内 runcmdaws ec2 modify-instance-attribute --no-source-dest-check として実行する形にしたのが v4 です。

v4 → v5:Route Table 自動更新の試行(route_table_ids_csv)

fck-nat の AMI には fck-nat.confroute_table_ids_csv 経由で Route Table を自動更新する仕組みが用意されています。v5 ではこれを試したのですが、当社の構成では条件によって反映が遅延する場面があり、安定運用を優先して別アプローチに切り替えました。

v5 → v6:aws ec2 replace-route の直叩きで安定化

現行 v6 では、cloud-config の runcmd 内で aws ec2 replace-route を直接叩いて、0.0.0.0/0 を自分の ENI に書き換える方式に変更。AMI 側のオプションには頼らず、IMDSv2 でメタデータを取りながらシェルで完結させたことで、挙動が読みやすく失敗時の切り分けも単純になりました。新しいインスタンスが起動して数秒で経路が自分に向く、安定動作です。

教訓

「AMI 側のオプションが用意されていても、最終的に自分が読めるシェルで書いた方が、運用面で事故が少ない」 ─ 同日中に 6 回書き直した結果として残ったのは、これでした。route_table_ids_csv のような便利機能は、内部実装が読めない箱として動くため、想定外の挙動が出たときに切り分けが難しくなります。挙動の透明性は、実運用での安心感を大きく左右する要素です。

fck-nat が向かないケース

ここまで fck-nat の良さに寄った書き方をしてきましたが、大前提として コストを気にしないのであれば、NAT Gateway のほうが圧倒的に安全で運用も楽です。マネージド・自動冗長化・自動スケール・運用負荷ゼロ ── これらは fck-nat ではトレードオフとして手放す部分です。以下の条件に当てはまる場合は特に、本記事の構成は採用せず NAT Gateway を素直に使うべきです。

A. 急変動・大規模なトラフィック

NAT Gateway が AWS 側で自動拡張するのに対し、fck-nat の帯域は 採用したインスタンスタイプで固定されます。インスタンスタイプを上げれば対応できますが、変更時にダウンタイムが発生し、高帯域インスタンスを使う規模になるとコスト優位性も消えます。トラフィック急変動への備えが必要なシステムでは NAT Gateway に分があります

B. 単一障害点になるため、高可用性が要件のシステム

本記事の構成(単一インスタンス・単一 AZ)は そのまま単一障害点になります。ASG self-healing で自動復旧はしますが、新インスタンス起動までの数分間は外向き通信が止まる前提です。年間ダウンタイム 1 時間以下のような要件では、AlterNAT 系のフェイルオーバー型構成(自前 NAT をプライマリで動かし、障害時に NAT Gateway へフェイルオーバーする Lambda 連携)を別途検討してください。当社は 「fck-nat 障害時は外向き通信を必要とするリクエストだけがエラーになり、外部通信が不要なリクエストには影響しない」という前提で「数分の瞬断は許容できる」と判断し、単一 AZ で採用しています。

fck-nat が向くのは

「外向き通信は中小規模、可用性は数分の瞬断を許容、自前 EC2 の運用は許容範囲」のシステム。SaaS の IP ホワイトリストへの単発接続、社内ツールの外向き API 呼び出し、開発・検証環境での費用削減 ── このあたりが手堅いハマりどころです。本記事の事例も「外向き通信は限定的、ECS タスク数も多くない、IP 固定だけは絶対要件」というプロファイルでした。

運用上の注意と現状の改善余地

ここまで「fck-nat は実運用で動く」前提で書いてきましたが、当社の現状の構成にも改善余地は残っています。同じ構成を真似する方が事前に把握しておけるよう、率直に開示します。

9-1. 単一 AZ 採用の判断と、その限界

fck-nat はAZ 障害が起きると確実に通信が止まります(対象 AZ 内のインスタンスが落ちて、ASG が別 AZ に立てる作りになっていない)。当社が単一 AZ を選んだのは、対象システムの SLA が「数分の瞬断は許容、AZ 障害時の追従はベストエフォート」だったためです。

要件次第では、ASG の VPCZoneIdentifier に複数 AZ を指定して、AZ 障害時に別 AZ で起動させる構成や、AZ ごとに独立した fck-nat スタック + 独立した EIP を持つ構成を取るべきです(後者は IP 固定要件の本数が増える)。

9-2. cwagent_enabled=true のメトリクスが見当たらない

/etc/fck-nat.confcwagent_enabled=true を入れていますが、CloudWatch Metrics 側で fck-nat 由来のカスタムメトリクス(CWAgent namespace のネットワーク統計など)が見つからない状態です。AMI 側の cwagent 起動の挙動か、IAM の cloudwatch:PutMetricData 権限の有無の問題かは未確認で、これも改善余地として残しています。

9-3. 「自前運用」で発生する追加責任

NAT Gateway はマネージドだったため意識する必要がなかったOS パッチ適用 / AMI のバージョンアップが、fck-nat では運用責任に乗ってきます。新しい fck-nat AMI がリリースされたら Launch Template を更新して、ASG をローリング(といっても min=max=1 なので「いったん落として立て直す」だけ)する手順をチームで共有しておく必要があります。

本記事の構成は完成形ではありません。 単一 AZ 採用 / cwagent 未確認、いずれも運用しながら、要件と工数の優先度の中で受け入れている状態です。fck-nat の構成自体は安定していますが、「マネージドサービスを 1 段降りた分の運用責任」がここに現れています。同じ構成を選ぶ方は、自社の SLA とこの改善項目とを照らして判断してください。
Endnote

あとがき

本記事は MOOBON が運用するシステムの 1 つで、NAT Gateway を捨てて fck-nat に置き換えた実装記録です。「outbound IP を固定したい」要件は時々現場に降ってきますが、検索しても「NAT Gateway を立てる」記事ばかりで、その他の選択肢を実装と運用の両面で書いた一次情報は意外と少ないと感じていました。本記事で採用判断の材料が少しでも増やせていれば嬉しいです。

AWS のコスト最適化の総まとめは、姉妹記事 AWS の “見えない固定費” 月 $310 を見つけて回収するまで に整理しています。NAT Gateway → fck-nat の置換は、そこで紹介している 10 施策のうちの 1 つです。

AWS のコスト構造そのものを腰を据えて見直したい方は、MOOBON が公開している AWS コスト分析ツールや、Kinsta 運用サービス(WordPress 案件のクラウド集約)の事例も併せてご覧ください。

For your team

同じ構成のレビュー / AWS 設計相談が必要ですか?

本記事のような outbound IP 固定要件 + マネージドからの離脱のような判断は、要件と運用体制次第で正解が変わります。「自社のシステムにこの構成は合うか」「採用前に第三者レビューが欲しい」「AWS 全体のコスト構造を見直したい」 ── そんな段階のご相談を、設計レビュー / コスト診断 / 運用設計支援の形で承っています。

FAQ

よくある質問

QECS タスクに直接 EIP を貼って outbound IP を固定するのでは駄目ですか?fck-nat のような NAT 装置を別建てする必要は本当にありますか?
A

条件付きで可能ですが、現代の ECS の推奨構成だと詰まる部分が多いです。EC2 launch type で bridge / host ネットワークモードを使い、EC2 ホストに EIP を貼ると、ホストの NAT(MASQUERADE)経由でコンテナの outbound IP は EIP に固定できます。ただし awsvpc ネットワークモード(ECS の現代的な推奨。タスク単位で Security Group を当てられる)では、タスクごとに別 ENI が割り当てられるため、ホストの EIP はコンテナ通信に効きません。Fargate もタスク ENI への EIP 直貼りはサポート外で、Public Subnet 配置の動的 Public IP に頼るしかなく IP 固定要件には合いません。さらに、複数タスクを動かす場合は EC2 ホストが複数台になり「固定 IP が複数本」になりがち(SaaS のホワイトリスト管理も増える)、Public Subnet に ECS タスクを置くことになりセキュリティ要件と衝突しがち、ASG で AZ 分散したときの EIP の付け替え運用が結局 fck-nat と同じことを ECS ホスト側で再発明することになる、といった構造的な不利が積み重なります。「単一 EC2 ホスト / bridge モード / 1 タスク」のような小規模ユースケースなら NAT 装置不要の解として成立しますが、複数タスク・Private 隔離・固定 IP を 1 本に集約という前提だと、NAT 装置(NAT Gateway か fck-nat)を別建てする方が運用設計はシンプルになります。

QNAT Gateway を維持したまま、awslogs を使わずに直接 S3 へログを送ることで NAT のデータ処理料金を削減できますか?
A

技術的には可能です。ECS の FireLens で Fluent Bit をサイドカーとして動かし、`s3` 出力プラグインでログを直接 S3 に PUT する構成にすれば、S3 Gateway Endpoint があるかぎり NAT を経由せずに保存でき、NAT データ処理料金は構造的にゼロに近づきます。AWS 公式の `amazon/aws-for-fluent-bit` イメージに s3 出力プラグインが組み込まれています。ただし検索性のトレードオフがあります。CloudWatch Logs の Logs Insights で行っていたリアルタイム検索や運用調査は、S3 直送に切り替えると Athena / S3 Select 経由のクエリに置き換わり、起動も重く・小回りも効きにくくなります。「今のエラーログを見せて」を頻繁にやる運用だと検索性が大きく落ちる印象です。別の現実解として、`com.amazonaws.<region>.logs` の Interface Endpoint を入れる方法もあります。料金は AZ × $0.014/h ≒ 月 $10/AZ で、awslogs ドライバの運用はそのままで NAT を迂回でき、検索性は CloudWatch Logs のまま維持されます。判断軸としては、運用負荷を抑えたいなら Interface Endpoint($10/AZ/月)、転送量を最大限削減したいなら FireLens + S3 直送、というのが現実的な選び分けです。本記事の MOOBON のケースでは fck-nat 採用でデータ処理料金そのものをゼロにする方向に倒しましたが、NAT Gateway を維持するシステムでは上記 2 つも有効な選択肢になります。

Qfck-nat は実運用で使って大丈夫ですか?可用性 SLA はどれくらい見ておけばいいですか?
A

AWS マネージドの NAT Gateway は AZ ごとに自動冗長化され可用性 SLA 99.99% が保証されますが、fck-nat は単一インスタンス構成だとそのインスタンスが落ちれば通信は止まります。Auto Scaling Group(min=max=desired=1)で self-healing させても、新しいインスタンスが起動して経路が切り替わるまで数分の瞬断が発生します。MOOBON では「数分の瞬断は許容、その代わりコストと運用透明性を取る」要件のシステムで採用しています。年間ダウンタイム 1 時間以下のような要件のシステムでは、マルチ AZ の自前 NAT 構成 + Lambda での経路切替(AlterNAT 等)か、素直にマネージド NAT Gateway をマルチ AZ で並べることを推奨します。

Qfck-nat のインスタンスタイプは ARM(t4g.nano)と x86_64(t3a.micro)のどちらを選ぶべきですか?
A

新規導入なら fck-nat 公式が推奨する ARM(Graviton)系の t4g.nano を選ぶのが合理的です。月額が最も安く($3 台)、Linux カーネルで NAT を担う本用途では ARM ↔ x86_64 の互換性で困る場面はありません。MOOBON が x86_64 の t3a.micro を採用しているのは、社内に余剰の Reserved Instance が x86_64 系で残っており、それを活用したかったという個別事情です。RI を持っていない場合・新規アカウントでの導入の場合は、t4g.nano を選ぶことをおすすめします。

Q既存の NAT Gateway から fck-nat への切り替えはダウンタイムが発生しますか?
A

Private Subnet の Route Table の 0.0.0.0/0 を NAT Gateway の ID から fck-nat の ENI ID に書き換える瞬間に経路が切り替わるため、切り替え自体は通常 1 〜 数秒のレベルです。ただし fck-nat 側に EIP を貼るタイミングと SaaS 側の IP ホワイトリスト更新のタイミングがズレると、外向き通信が拒否される時間帯が発生します。MOOBON では(1)新しい EIP を確保して fck-nat 側に紐付ける、(2)接続先 SaaS のホワイトリストに新 EIP を追加してもらう(古い EIP も残してもらう)、(3)Route Table を切り替える、(4)旧 NAT Gateway を削除し古い EIP も外す、という順で運用上のダウンタイムを最小化しました。SaaS 側のホワイトリスト更新に時間が掛かる場合は、その期間は新旧両方の経路を有効にしておく猶予期間を設けるのが安全です。

Qfck-nat AMI のセキュリティパッチや AMI バージョンアップはどう運用しますか?
A

fck-nat AMI 配布元アカウント(568608671756)の AMI は、新バージョンがリリースされるたびに新しい AMI ID として公開されます。MOOBON では(1)定期的に新 AMI のリリースを確認し、(2)Launch Template の新バージョンを作成して新 AMI ID を設定し、(3)ASG の Launch Template バージョン参照を新版に切り替えて、(4)既存インスタンスをいったん落とす(ASG が新しいインスタンスを新 AMI で起動する)というローリング手順で更新しています。min=max=desired=1 構成のため厳密な無瞬断ローリングはできず、新インスタンスが立ち上がるまでの数分は通信が止まります。要件として無瞬断更新が必要なら、blue/green で 2 つの fck-nat スタックを切り替える運用を別途設計してください。

Q単一 AZ 構成で AZ 障害が起きたとき、外向き通信はどうなりますか?
A

本記事で開示した単一 AZ 構成では、配置先 AZ(当社の場合 ap-northeast-1a)が障害を起こすと外向き通信は止まります。ASG の VPCZoneIdentifier に複数 AZ を指定していれば、AZ 障害時に別 AZ で新インスタンスが起動して通信が復旧しますが、起動までの数分〜十数分は外向き通信が止まる前提です。AZ 障害でも瞬断ゼロを要求される場合は、AZ ごとに独立した fck-nat スタック + 独立した EIP を持って Route Table を AZ 別に持たせる構成、もしくはマネージドの NAT Gateway をマルチ AZ で並べる方が堅実です。

MOOBONISO/IEC 27001 CertificationIT導入補助金 支援事業者
Copyright © 2026 MOOBON, Inc. All Rights Reserved.
適用規格:ISO/IEC 27001:2022
適用範囲:Web 系システム設計支援 / 自社クラウドサービス開発・運用・保守 / 受託システム開発・運用・保守 / サーバ構築・運用・保守