AWS NAT GatewayでプライベートサブネットのEC2をインターネットに接続する方法|マルチAZ冗長設計とコスト最適化の実践手順

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)AWS(Amazon Linux) > AWS NAT GatewayでプライベートサブネットのEC2をインターネットに接続する方法|マルチAZ冗長設計とコスト最適化の実践手順
「プライベートサブネットのEC2から yum update を実行したら、インターネットに繋がらなくて困った」
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エンドポイントで迂回するとコスト削減できる


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

なぜプライベートサブネットの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 | +---------------------+--------------+------------------+---------+

パブリックサブネットのルートテーブルに「0.0.0.0/0 → IGW」のルートが存在することも確認しておきます。このIGWが存在しないと、NAT GW自身がインターネットへ出られません。

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" }

EIPはNAT Gatewayに関連付けられている間は追加料金不要です。EC2に関連付けられていない遊休EIPには/bin/bash.005/時間の課金が発生するため、不要なEIPを解放する習慣をつけてください。

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 | +-------------------------+-----------+----------------+

コマンドはNAT GWが利用可能になるまでポーリングして完了を待ちます。スクリプト化する際に sleep で待機するより確実です。

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

221.254.141.78 で返ってくるIPがNAT GatewayのEIPと一致すれば、SNA変換が正常に機能しています。プライベートEC2のプライベートIPが外部に出ることはありません。LinuxサーバーのDNS設定についてはDNS(/etc/resolv.conf)設定の基本も参考にしてください。

マルチ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 | +-------------------------+--------------------+----------------+

これでAZ障害が発生しても、残ったAZのNAT GWが独立して動き続けます。1a AZが落ちても1b AZのEC2は1b AZのNAT GWを使い続け、アウトバウンド通信が維持されます。

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エンドポイント経由になる

Gateway型VPCエンドポイントはデータ転送量に対する追加料金が発生しません(Gateway型はInterface型と異なり無料)。S3やDynamoDBのアクセスが多い構成では、最初に導入を検討してください。

トラブルシュート|プライベート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
AWSのプライベートサブネット設計においてNAT Gatewayは必須コンポーネントです。シングルAZ構成のリスクを理解した上で、本番環境ではAZごとに1台のNAT Gatewayを配置するマルチAZ構成を標準としてください。コストが気になる場合は、S3・DynamoDBの通信をGateway型VPCエンドポイントで迂回させることを最初に検討しましょう。

VPCの基本設計についてはAWSのLinux環境構築とVPC設計入門も合わせて参照してください。

NAT Gatewayの使い方だけでなく、AWSを「実務の型」として身につけませんか?

aws ec2 create-nat-gateway のコマンドは調べれば分かります。でも「どのAZに何台置くべきか」「コストとのバランスをどうとるか」を、自信を持って答えられますか?
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。

「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。