AWSでVPCを設計するとき、セキュリティのためにEC2をプライベートサブネットに置くのは正解です。しかし、そのままではインターネットへのアウトバウンド通信ができず、パッケージのアップデートや外部APIへの接続が詰まってしまいます。
この記事では、プライベートサブネットのEC2をインターネットに接続するために使う「NAT Gateway」の仕組み・作成手順・マルチAZ冗長設計・コスト最適化まで、AWS CLIを使って実践的に解説します。Amazon Linux 2023 / RHEL 9.4 で動作確認しています。
この記事のポイント
・NAT GatewayはパブリックサブネットにEIPと共に作成する
・プライベートサブネットのルートに0.0.0.0/0→NAT GWを追加する
・可用性確保のためAZごとに1台のNAT Gatewayを配置する
・S3はGateway型VPCエンドポイントで迂回するとコスト削減できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜプライベートサブネットのEC2にNAT Gatewayが必要なのか
AWSのVPC設計では、インターネットから直接アクセスされるリソース(ALBなど)はパブリックサブネットに、データベースやアプリサーバーはプライベートサブネットに配置するのが基本パターンです。プライベートサブネットのEC2は、インターネットゲートウェイ(IGW)へのルートを持たないため、原則として外部と直接通信できません。しかし実際の運用では、以下の用途でアウトバウンド通信が必要になります。
・yum / dnf / apt によるパッケージアップデート(リポジトリへのHTTPS接続)
・AWS Systems Manager Agent のエンドポイント接続
・外部APIへのHTTPS呼び出し(決済・SMS・SaaS連携など)
・Dockerイメージの Pull(Docker Hub 等)
この「外には出たいが、外からは入られたくない」という要件を満たすのがNAT Gateway(NAT GW)です。NAT GWはパブリックサブネットに置き、プライベートサブネットのEC2からの通信を受け取って、自身に関連付けたElastic IP(EIP)を使ってインターネットへ中継します。EC2のプライベートIPが外部に露出することはなく、送信元IPはNAT GWのEIPに変換(SNAT)されます。
NAT GatewayとNAT Instanceの違い
AWSでは「NAT Gateway」と「NAT Instance(EC2ベース)」の2種類が選択肢として存在します。現在の実務では、ほぼ全ての場合でNAT Gatewayを選択します。・NAT Gateway: AWSのマネージドサービス。高可用性・最大100Gbpsのスループットに対応。帯域幅の自動スケーリング、パッチ適用不要で運用コストが低い
・NAT Instance: 自前のEC2でNATを実装。フレキシビリティがある一方、単一障害点(SPOF)になるリスクがあり、OSのメンテナンスも必要
NAT Instanceが選択肢になるのは、超小規模の個人プロジェクトでコストを1円単位で削りたい場合のみです。月5前後のNAT Gatewayコストを許容できるなら、本番環境ではNAT Gatewayの一択です。
NAT Gatewayを作成してプライベートEC2からインターネットに接続する手順
前提として、以下が既に作成されているものとします。・VPC(例: 10.0.0.0/16、vpc-0a1b2c3d4e5f6)
・パブリックサブネット(IGWへのルートあり、subnet-pub-1a0001)
・プライベートサブネット(IGWなし、subnet-prv-1a0001)
・プライベートサブネット上に配置されたEC2
1. 前提環境の確認(VPC・サブネット・IGW)
まず現在のVPCとサブネット構成を確認します。# VPC一覧を確認する $ aws ec2 describe-vpcs --query 'Vpcs[*].[VpcId,CidrBlock,Tags[?Key==].Value|[0]]' --output table -------------------------------------------------- | DescribeVpcs | +--------------------+--------------+----------+ | vpc-0a1b2c3d4e5f6 | 10.0.0.0/16 | prod-vpc | +--------------------+--------------+----------+ # サブネット一覧を確認する $ aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-0a1b2c3d4e5f6" --query 'Subnets[*].[SubnetId,CidrBlock,AvailabilityZone,Tags[?Key==].Value|[0]]' --output table ---------------------------------------------------------------------------- | DescribeSubnets | +---------------------+--------------+------------------+---------+ | subnet-pub-1a0001 | 10.0.1.0/24 | ap-northeast-1a | pub-1a | | subnet-pub-1b0001 | 10.0.2.0/24 | ap-northeast-1b | pub-1b | | subnet-prv-1a0001 | 10.0.11.0/24 | ap-northeast-1a | prv-1a | | subnet-prv-1b0001 | 10.0.12.0/24 | ap-northeast-1b | prv-1b | +---------------------+--------------+------------------+---------+
2. Elastic IPアドレスを払い出す
NAT GatewayにはElastic IP(固定パブリックIP)が必要です。NAT GW用に1つ払い出します。# EIPを払い出す(VPC用として) $ aws ec2 allocate-address --domain vpc --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=nat-gw-eip-1a}]' { "PublicIp": "54.250.xxx.xxx", "AllocationId": "eipalloc-0a1b2c3d4e5f60001", "Domain": "vpc", "NetworkBorderGroup": "ap-northeast-1" }
3. NAT GatewayをCLIで作成する
NAT Gatewayはパブリックサブネットに作成します。よくある間違いはプライベートサブネットに作ってしまうことです。プライベートサブネットに作ったNAT GWはIGWに到達できないため、インターネット通信が一切できません。# パブリックサブネット(pub-1a)にNAT Gatewayを作成する $ aws ec2 create-nat-gateway --subnet-id subnet-pub-1a0001 --allocation-id eipalloc-0a1b2c3d4e5f60001 --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=nat-gw-1a}]' { "NatGateway": { "NatGatewayId": "nat-0a1b2c3d4e5f60001", "SubnetId": "subnet-pub-1a0001", "VpcId": "vpc-0a1b2c3d4e5f6", "State": "pending" } } # Stateが available になるまで待機する(通常1~2分) $ aws ec2 wait nat-gateway-available --filter "Name=nat-gateway-id,Values=nat-0a1b2c3d4e5f60001" # 完了後に状態を確認する $ aws ec2 describe-nat-gateways --nat-gateway-ids nat-0a1b2c3d4e5f60001 --query 'NatGateways[*].[NatGatewayId,State,NatGatewayAddresses[0].PublicIp]' --output table +-------------------------+-----------+----------------+ | nat-0a1b2c3d4e5f60001 | available | 54.250.xxx.xxx | +-------------------------+-----------+----------------+
4. プライベートサブネットのルートテーブルを更新する
NAT Gatewayを作成しただけでは通信できません。プライベートサブネットのルートテーブルに「0.0.0.0/0 → NAT GW」のルートを追加する必要があります。# プライベートサブネット(prv-1a)のルートテーブルIDを確認する $ aws ec2 describe-route-tables --filters "Name=association.subnet-id,Values=subnet-prv-1a0001" --query 'RouteTables[*].RouteTableId' --output text rtb-0prv1a000001 # 現在のルートを確認する(デフォルトはVPC内ローカルのみ) $ aws ec2 describe-route-tables --route-table-ids rtb-0prv1a000001 --query 'RouteTables[*].Routes[*].[DestinationCidrBlock,GatewayId,State]' --output table +---------------+----------+--------+ | 10.0.0.0/16 | local | active | +---------------+----------+--------+ # NAT Gatewayへのルートを追加する $ aws ec2 create-route --route-table-id rtb-0prv1a000001 --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-0a1b2c3d4e5f60001 {"Return": true} # ルートテーブルの最終状態を確認する $ aws ec2 describe-route-tables --route-table-ids rtb-0prv1a000001 --query 'RouteTables[*].Routes[*].[DestinationCidrBlock,NatGatewayId,State]' --output table +----------------+-------------------------+---------+ | 0.0.0.0/0 | nat-0a1b2c3d4e5f60001 | active | | 10.0.0.0/16 | local | active | +----------------+-------------------------+---------+
5. プライベートEC2からの疎通確認
プライベートサブネットのEC2にSSHまたはSession Managerで接続し、アウトバウンド通信を確認します。# プライベートEC2にSession Managerで接続後、実施する確認 # 1. グローバルIPがNAT GWのEIPになっているか確認する $ curl -s https://checkip.amazonaws.com 54.250.xxx.xxx # NAT GatewayのEIPが返れば成功 # 2. HTTPS疎通を確認する $ curl -s https://example.com -o /dev/null -w "%{http_code} " 200 # 3. DNSが解決できるか確認する $ nslookup example.com Server: 10.0.0.2 Address: 10.0.0.2#53 Non-authoritative answer: Name: example.com Address: 93.184.216.34
マルチAZ冗長設計|AZ障害を想定したNAT Gateway配置
6. シングルAZ構成の落とし穴
コストを抑えようと1a AZにのみNAT Gatewayを配置し、1b AZのプライベートサブネットも1a AZのNAT GWを経由させた場合、1a AZで障害が発生すると1b AZのEC2も含めてアウトバウンド通信が全て停止します。ALBやRDSのフェイルオーバーが正常に動いていても、アプリケーションが外部APIにアクセスできず、意図せぬサービス停止が起きます。これはよくある設計ミスの一つです。
加えて、AZをまたいだNAT GW経由の通信にはAZ間データ転送料金(/bin/bash.01/GB)が発生します。可用性とコストのトレードオフを理解した上で構成を決める必要があります。
マルチAZ全体の冗長設計パターンについてはAWSマルチAZ冗長設計の実践ガイドでも詳しく解説しています。
7. 各AZにNAT Gatewayを配置する実装手順
本番環境での推奨構成は「AZごとに1台のNAT Gatewayを配置し、各AZのプライベートサブネットはそのAZのNAT GWを使う」です。# 1b AZ用のEIPを払い出す $ aws ec2 allocate-address --domain vpc --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=nat-gw-eip-1b}]' # AllocationId: eipalloc-0a1b2c3d4e5f60002 # 1b AZのパブリックサブネットにNAT Gatewayを作成する $ aws ec2 create-nat-gateway --subnet-id subnet-pub-1b0001 --allocation-id eipalloc-0a1b2c3d4e5f60002 --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=nat-gw-1b}]' # NatGatewayId: nat-0a1b2c3d4e5f60002 # 完了を待機する $ aws ec2 wait nat-gateway-available --filter "Name=nat-gateway-id,Values=nat-0a1b2c3d4e5f60002" # 1b AZのプライベートサブネットのルートテーブルを1b NATに向ける # (1a AZのprv-1aは既に1a AZのNAT GWを向いているので変更不要) $ aws ec2 create-route --route-table-id rtb-0prv1b000002 --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-0a1b2c3d4e5f60002 # 最終的なNAT Gateway一覧を確認する $ aws ec2 describe-nat-gateways --filter "Name=vpc-id,Values=vpc-0a1b2c3d4e5f6" "Name=state,Values=available" --query 'NatGateways[*].[NatGatewayId,SubnetId,NatGatewayAddresses[0].PublicIp]' --output table +-------------------------+--------------------+----------------+ | nat-0a1b2c3d4e5f60001 | subnet-pub-1a0001 | 54.250.xxx.xxx | | nat-0a1b2c3d4e5f60002 | subnet-pub-1b0001 | 13.112.yyy.yyy | +-------------------------+--------------------+----------------+
NAT Gatewayのコスト構造と最適化
8. 料金の仕組みを理解する
NAT Gatewayの料金は2種類から構成されます(ap-northeast-1 東京リージョン、2026年7月時点)。・時間料金: /bin/bash.062/時間(1台につき。1か月稼働で約5)
・データ処理料金: /bin/bash.062/GB(NAT GWが処理したデータ量)
マルチAZで2台配置すると時間料金は2倍(月約0)になります。開発・検証環境ではコスト削減のため夜間にNAT GWを削除してEIPのみ保持し、朝に再作成する運用を取るチームもあります(EIPの保持コストは/bin/bash.005/時間)。本番環境ではこのような削除運用は行わないことをおすすめします。
9. VPCエンドポイントとの組み合わせでS3転送コストを削減する
S3やDynamoDBへのアクセスは、NAT Gatewayを経由させる必要はありません。Gateway型VPCエンドポイントを作成すると、S3・DynamoDBへの通信がNAT GWをバイパスしてVPC内で直接ルーティングされます。大量のS3アクセスがある環境(バックアップ・ログ転送・画像処理など)では、VPCエンドポイントの導入だけでデータ処理料金を数十%削減できるケースがあります。ポートの疎通確認にはLinuxのssコマンドによるポート確認も活用してください。
# S3向けGateway型VPCエンドポイントを作成する(無料) $ aws ec2 create-vpc-endpoint --vpc-id vpc-0a1b2c3d4e5f6 --service-name com.amazonaws.ap-northeast-1.s3 --route-table-ids rtb-0prv1a000001 rtb-0prv1b000002 --tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=endpoint-s3}]' # 作成後、プライベートサブネットのルートテーブルを確認する $ aws ec2 describe-route-tables --route-table-ids rtb-0prv1a000001 --query 'RouteTables[*].Routes[*].[DestinationCidrBlock,GatewayId,State]' --output table +------------------------+----------------------------+---------+ | 0.0.0.0/0 | nat-0a1b2c3d4e5f60001 | active | | 10.0.0.0/16 | local | active | | pl-61a54008 (S3 Prefix)| vpce-0a1b2c3d4e5f6xxxx | active | +------------------------+----------------------------+---------+ # pl-xxxxxxxx はS3のPrefix Listを表す # S3への通信は自動的にVPCエンドポイント経由になる
トラブルシュート|プライベートEC2からインターネットに出られない時の調査手順
「NAT GWを設定したはずなのにプライベートEC2から外に出られない」場合の切り分け手順です。1. NAT GatewayのStateを確認する
$ aws ec2 describe-nat-gateways --nat-gateway-ids nat-0a1b2c3d4e5f60001 --query 'NatGateways[*].[NatGatewayId,State,FailureMessage]' --output table # State が available であることを確認する # deleted や failed の場合は再作成が必要 # pending 中はルート追加作業を先に進めないこと
2. ルートテーブルの設定を確認する
最も多い原因は「ルートテーブルの設定ミス」です。2つの確認ポイントがあります。# プライベートサブネットに関連付けられたルートテーブルを確認する $ aws ec2 describe-route-tables --filters "Name=association.subnet-id,Values=subnet-prv-1a0001" --query 'RouteTables[*].Routes[*].[DestinationCidrBlock,NatGatewayId,State]' --output table # 確認ポイント: # 1. 0.0.0.0/0 のルートが存在するか # 2. NatGatewayId が正しい NAT GW を指しているか # 3. State が active か(blackhole はNAT GWが削除済みを意味する) # ルートが blackhole になっていたら対処する $ aws ec2 replace-route --route-table-id rtb-0prv1a000001 --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-0a1b2c3d4e5f60001
3. セキュリティグループのアウトバウンドルールを確認する
ルートテーブルが正しくても、EC2のセキュリティグループがアウトバウンド通信をブロックしていることがあります。# EC2に割り当てられたSGのアウトバウンドルールを確認する $ aws ec2 describe-security-groups --group-ids sg-0ec2prv001 --query 'SecurityGroups[*].IpPermissionsEgress[*].[IpProtocol,FromPort,ToPort,IpRanges[0].CidrIp]' --output table +----------+----------+--------+-------------+ | -1 | None | None | 0.0.0.0/0 | +----------+----------+--------+-------------+ # IpProtocol が -1(全プロトコル)で 0.0.0.0/0 許可があれば問題なし # 443/tcp のみ許可になっていると、ICMP(ping)などが通らない場合がある
本記事のまとめ
NAT Gatewayの作成から冗長設計・コスト最適化まで、実務で必要な手順を解説しました。| やりたいこと | コマンド |
|---|---|
| EIPを払い出す | aws ec2 allocate-address --domain vpc |
| NAT Gatewayを作成する | aws ec2 create-nat-gateway --subnet-id pub-subnet-id --allocation-id eip-alloc-id |
| NAT GW完成を待機する | aws ec2 wait nat-gateway-available --filter "Name=nat-gateway-id,Values=nat-id" |
| プライベートルートを追加する | aws ec2 create-route --route-table-id rtb-id --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-id |
| 疎通確認する | curl -s https://checkip.amazonaws.com |
| VPCのNAT GW一覧を確認する | aws ec2 describe-nat-gateways --filter "Name=vpc-id,Values=vpc-id" "Name=state,Values=available" |
| S3向けVPCエンドポイントを作成する | aws ec2 create-vpc-endpoint --vpc-id vpc-id --service-name com.amazonaws.ap-northeast-1.s3 --route-table-ids rtb-id |
VPCの基本設計についてはAWSのLinux環境構築とVPC設計入門も合わせて参照してください。
NAT Gatewayの使い方だけでなく、AWSを「実務の型」として身につけませんか?
aws ec2 create-nat-gateway のコマンドは調べれば分かります。でも「どのAZに何台置くべきか」「コストとのバランスをどうとるか」を、自信を持って答えられますか?
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:AWS VPCのサブネット設計入門|パブリック・プライベート分離とルートテーブルをCLIで実装する方法
- この記事の属するカテゴリ:AWS(Amazon Linux)へ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます