結論

Amazon VPC は、AWS の中に作る自分専用の仮想ネットワークです。サブネットに付けたルートテーブルに「0.0.0.0/0 → インターネットゲートウェイ」の行があればパブリックサブネット、無ければプライベートサブネットになります。

この記事でわかること

  • VPC・サブネット・ルートテーブル・IGW・NAT の関係と、パブリック/プライベートの決まり方
  • moto と AWS CLI で作った VPC の出力と、ip netns で「外へ出られる/出られない」を再現した ping・tcpdump
  • CIDR の決め方の計算、セキュリティグループと NACL の違い、料金の考え方の判断表

2026年10月29日更新|moto 5.1.22・AWS CLI 1.44.87・iproute2 6.1.0で実行確認

VPC は「AWS の中に借りた、自分だけの区画」です。区画の中をサブネットで部屋に分け、部屋ごとのルートテーブル(道案内の表)で「外へ出る扉」を決めます。最初に全体の形を図で示します。

flowchart TB
    NET((インターネット))
    IGW[インターネット<br>ゲートウェイ]
    subgraph VPC[VPC 10.0.0.0/16]
        subgraph PUB[パブリック 10.0.1.0/24]
            WEB[Web<br>公開IPあり]
            NAT[NAT<br>ゲートウェイ]
        end
        subgraph PRI[プライベート 10.0.11.0/24]
            DB[DB・アプリ]
        end
    end
    NET <--> IGW
    IGW <--> WEB
    DB -->|外向きだけ| NAT
    NAT --> IGW

よく調べられることの答えを先にまとめます。

知りたいこと 答え 詳しい節
VPCとは AWS の中に作る、論理的に切り離された自分専用の仮想ネットワーク VPCとは
VPC サブネットとは VPC の IP アドレスの範囲を小分けしたもの。1つのアベイラビリティーゾーン(AZ)の中に置く サブネットとルートテーブル
パブリックとプライベートの違い ルートテーブルに IGW への経路があるかどうか。名前の設定ではない サブネットとルートテーブル
IGW と NAT ゲートウェイの違い IGW は外と双方向、NAT は中から外への片道だけ IGWとNATゲートウェイの違い
CIDR はどう決める /16 を取り、AZ ごと・役割ごとに /20〜/24 に分ける。他と重ねない CIDRとサブネットの決め方
セキュリティグループと NACL の違い SG はインスタンス単位で戻りを自動で許可、NACL はサブネット単位で戻りも書く SGとネットワークACLの違い
VPC の料金 VPC 自体は追加料金なし。NAT ゲートウェイ・パブリック IPv4 などが有料 VPCの料金の考え方
作り方の手順(AWS CLI) VPC→サブネット→IGW→ルートテーブル→関連付けの順 AWS CLIで作った出力

確認環境:Ubuntu 24.04.5 LTS(カーネル 6.18.44)の上で、本物の AWS には接続せず、AWS のモック(まねをする偽物のサーバー)である moto 5.1.22 をサーバーモードで 127.0.0.1 に起動し、AWS CLI 1.44.87(botocore 1.42.97・Python 3.9.25 の venv)から VPC・サブネット・IGW・ルートテーブル・NAT ゲートウェイ・セキュリティグループを作成・削除しました。認証情報は作業用のダミーの値だけを使っています。パブリック/プライベートの違いは、Linux の ip netns(ネットワークを分けた小部屋)を7つ作り、iproute2 6.1.0・iptables 1.8.10(nf_tables)で「VPC ルーター」「IGW」「NAT」「インターネット」を再現して、ping(iputils 20240117)・curl 8.5.0・tcpdump 4.99.4 で確かめました。CIDR の計算は Python 3.13.18 の ipaddress モジュールです。AWS 側の仕様(サブネットの大きさ・予約アドレス・デフォルト VPC・クォータ・NACL のエフェメラルポート・料金)は AWS の公式ドキュメントと料金ページで確かめ、moto の動きが公式と違う点は本文に書いています。図は mermaid 11.16.0 で描画を確かめました(確認日 2026年10月29日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「VPCとは?AWSのサブネット・IGW・NATの関係を手元で再現」

VPCとは(Amazon VPCの意味と全体像)

この節では、VPC が何の略で、何をするための仕組みなのかが分かります。

VPC は Virtual Private Cloud の略で、AWS の中に「論理的に切り離された、自分で定義する仮想ネットワーク」を作るサービスです。 AWS の公式ドキュメントは、自社のデータセンターで運用する従来のネットワークによく似たもので、そこに AWS のリソース(EC2・RDS・ロードバランサーなど)を置ける、と説明しています。

家にたとえると、VPC は「敷地」、サブネットは「部屋」、ルートテーブルは「部屋ごとの道案内の表」、インターネットゲートウェイ(IGW)は「表通りへの玄関」、NAT ゲートウェイは「中からは出られるが、外からは入れない勝手口」です。セキュリティグループは「各部屋の住人が持つ合鍵の規則」、ネットワーク ACL は「部屋の入口の門番」にあたります。

VPC で決められること

  • IP アドレスの範囲:VPC 全体の範囲(例:10.0.0.0/16)と、サブネットごとの範囲を自分で決める。
  • 経路:サブネットからの通信をどこへ送るかを、ルートテーブルで決める。
  • 外との出入り口:インターネット(IGW)、外向きだけ(NAT)、社内ネットワーク(VPN・Direct Connect)、他の VPC(ピアリング・Transit Gateway)、AWS のサービス(VPC エンドポイント)を必要な分だけ付ける。
  • 通してよい通信:セキュリティグループとネットワーク ACL で、ポートと送信元を絞る。

VPC は「リージョン」単位で作り、サブネットは「AZ(アベイラビリティーゾーン。リージョンの中の独立したデータセンター群)」単位で作ります。 1つの VPC は東京リージョンの中の複数の AZ にまたがれますが、1つのサブネットは1つの AZ からはみ出せません。

Google Cloud の「VPC」との関係

「VPC」という言葉は AWS だけのものではなく、Google Cloud にも VPC があります。この記事は AWS の Amazon VPC について書いています。Google Cloud の公式ドキュメントは、VPC ネットワークをリージョンのサブネットで構成される「グローバル リソース」と説明しており、AWS(VPC はリージョン、サブネットは AZ)とは単位が異なります。

VPCを構成する要素の一覧

この節では、VPC の中に出てくる部品の名前と役割が一覧で分かります。

最初に覚えるのは、サブネット・ルートテーブル・IGW・NAT ゲートウェイ・セキュリティグループの5つです。 残りは、必要になったときに足す部品です。

1

サブネット

VPC の IP 範囲を小分けした「部屋」。1つの AZ に属する。サーバーはここに置く。

大きさは /16〜/28

2

ルートテーブル

「この宛先はこの出口へ」の表。サブネットごとに1つ関連付く。

パブリックかどうかを決める

3

インターネットゲートウェイ

VPC とインターネットをつなぐ玄関。外と双方向に通信できる。

VPC に1つアタッチ

4

NAT ゲートウェイ

プライベートサブネットから外へ「出るだけ」の勝手口。外からは入れない。

時間とデータ量で課金

5

セキュリティグループ

インスタンス(正確にはネットワークインターフェイス)ごとの許可リスト。

戻りの通信は自動で許可

6

ネットワーク ACL

サブネットの入口の許可・拒否リスト。番号の小さい順に判定。

戻りの通信も書く

部品 役割 いつ使う
Elastic IP 固定のパブリック IPv4 アドレス NAT ゲートウェイ(パブリック型・ゾーン型)や、IP を変えたくないサーバー
VPC エンドポイント インターネットを通らずに S3 などの AWS サービスへ行く プライベートサブネットから S3・DynamoDB・各種 API を使うとき
VPC ピアリング 2つの VPC を1対1でつなぐ つなぐ VPC が少ないとき
Transit Gateway 多数の VPC・VPN・Direct Connect をつなぐ中継の拠点(ハブ) VPC が多い、社内網ともつなぐとき
Site-to-Site VPN 社内ネットワークと VPC を暗号化してつなぐ オンプレミスと AWS を併用するとき
VPC フローログ ネットワークインターフェイスを出入りした通信の記録 「届いているか」「どこで拒否されたか」を調べるとき

サブネットとルートテーブル(パブリックとプライベートの違い)

この節では、VPC のサブネットとは何か、パブリックサブネットとプライベートサブネットが何で決まるのかが分かります。

サブネットは「VPC の IP アドレスの範囲を小分けしたもの」で、必ず1つの AZ の中に収まります。 AWS の公式ドキュメントは「各サブネットは1つの AZ の中に完全に収まり、AZ をまたげない」と書いています。複数の AZ に分けて同じ役割のサブネットを作るのは、AZ が1つ止まっても動き続けるためです。

パブリック/プライベートは「ルートテーブル」で決まる

公式ドキュメントは、サブネットの種類をルーティングの設定で決まるものとして4つに分けています。

種類 ルートテーブルの中身 できること
パブリックサブネット IGW への直接の経路がある(0.0.0.0/0 → igw-…) インターネットと通信できる(パブリック IP が要る)
プライベートサブネット IGW への直接の経路が無い 外へ出るには NAT が要る
VPN 専用サブネット 仮想プライベートゲートウェイ経由の VPN への経路だけ 社内ネットワークとだけ通信
分離されたサブネット VPC の外への経路が無い 同じ VPC の中とだけ通信

「パブリックサブネット」というチェックボックスはありません。 サブネットの名前に public と付けても、ルートテーブルに IGW への行が無ければプライベートとして振る舞います。逆に、名前が private でも IGW への行があればパブリックです。

ルートテーブルの読み方

ルートテーブルは「宛先(Destination)」と「ターゲット(Target。次に渡す先)」の2列の表です。VPC を作ると、VPC の範囲あての local の行が必ず入り、VPC の中どうしはこの行で届きます。宛先が重なるときは、いちばん細かい(プレフィックスの長い)行が選ばれます。

宛先 ターゲット 意味
10.0.0.0/16 local VPC の中あては VPC の中で届ける(消せない)
0.0.0.0/0 igw-… それ以外は全部インターネットへ(パブリック)
0.0.0.0/0 nat-… それ以外は NAT ゲートウェイへ(プライベートの外向き)
pl-…(S3 のプレフィックスリスト) vpce-… S3 あてはゲートウェイエンドポイントへ

サブネットに明示的に関連付けたルートテーブルが無いときは、VPC のメインルートテーブルが使われます。メインルートテーブルに IGW への行を足すと、関連付けを忘れたサブネットまでパブリックになるため、メインは local だけにしておき、パブリック用・プライベート用を別に作って明示的に関連付けるのが安全です。

インターネットゲートウェイとNATゲートウェイの違い

この節では、IGW と NAT ゲートウェイがそれぞれ何をして、なぜ両方が要るのかが分かります。

IGW は「外と双方向」、NAT ゲートウェイは「中から外への片道だけ」です。 NAT ゲートウェイについて、公式ドキュメントは「プライベートサブネットのインスタンスは VPC の外のサービスに接続できるが、外のサービスはそのインスタンスへの接続を始められない」と説明しています。

同じ「外へ出る」でも、外から入れるかが違う

インターネットゲートウェイパブリック IP を持つリソースが、外へ出る・外から入られるの両方をする。Web サーバー・ロードバランサー向け
↔
NAT ゲートウェイプライベート IP しか持たないリソースが、外へ出るだけ。OS の更新・外部 API の呼び出し向け。外からは入られない

見分ける問い:「インターネットから接続を始められてよいか」

IGW は「パブリック IP」と組で働く

IGW をアタッチしてルートテーブルに経路を書いても、サーバー自身にパブリック IPv4 アドレス(または Elastic IP)が無いと、インターネットとは通信できません。 IGW は、プライベート IP とパブリック IP を1対1で付け替える役もしているためです。この点は、後の ip netns の再現で、同じパブリックサブネットにいるのにパブリック IP の無いサーバーだけ外へ出られない様子として確かめます。

NAT ゲートウェイの置き場所と種類

  • パブリック型(既定):パブリックサブネットに作り、作成時に Elastic IP を付ける。プライベートサブネットのルートテーブルに「0.0.0.0/0 → nat-…」を書く。
  • プライベート型:Elastic IP を付けられない。他の VPC や社内ネットワークへの通信で、送信元アドレスをそろえたいときに使う。
  • リージョン型(Regional NAT gateway):公式ドキュメントでは、従来の NAT ゲートウェイを「ゾーン型(zonal)」と呼び分け、リージョン型は AZ をまたいで自動で広がり、パブリックサブネットを要しない独立したリソースと説明しています(プライベート型には対応していません)。

ゾーン型の NAT ゲートウェイは1つの AZ の中で動くため、AZ ごとに NAT を置かないと、その AZ が止まったときに他の AZ のプライベートサブネットも外へ出られなくなります。可用性と料金の釣り合いで、「本番は AZ ごと(またはリージョン型)、開発は1つ」と分けることがよくあります。

VPCをAWS CLIで作った出力(motoで再現)

この節では、VPC からセキュリティグループまでを AWS CLI で作ったときに、実際に何が返るのかが分かります。

本物の AWS には接続せず、moto のサーバーを 127.0.0.1 に起動して、AWS CLI の接続先をそこへ向けました。 鍵はダミーで、設定ファイルも作業場所に置いています。1行ずつの詳しい手順やスクリプト化は、関連記事「AWS CLIでVPCを作成する手順|サブネットからIGWまで一式」で扱っています。この記事では、全体の関係が見える出力にしぼります。

$ moto_server -H 127.0.0.1 -p 51340
 * Running on http://127.0.0.1:51340

# 接続先とダミーの鍵(作業場所の設定ファイル)
$ export AWS_ENDPOINT_URL=http://127.0.0.1:51340
$ export AWS_CONFIG_FILE=./aws/config AWS_SHARED_CREDENTIALS_FILE=./aws/credentials
1

VPC を作る

範囲(CIDR)を決めて作る。メインルートテーブル・デフォルトのセキュリティグループ・ネットワーク ACL が一緒にできる。

create-vpc

2

サブネットを作る

AZ と範囲を指定する。この時点ではパブリックもプライベートも無い。

create-subnet

3

IGW を作って VPC にアタッチ

作っただけでは使われない。ルートテーブルに書いて初めて通る。

create-internet-gateway・attach-internet-gateway

4

ルートテーブルを作り、経路を書き、関連付ける

パブリック用に 0.0.0.0/0 → IGW。サブネットに関連付けた時点でパブリックになる。

create-route-table・create-route・associate-route-table

5

NAT とプライベート用のルートテーブル

Elastic IP を取り、パブリックサブネットに NAT を作り、プライベート用の表に 0.0.0.0/0 → NAT。

allocate-address・create-nat-gateway

6

セキュリティグループ

Web 用に 443 を許可、DB 用に「Web のセキュリティグループから 3306」を許可。

create-security-group・authorize-security-group-ingress

VPC の作成

$ aws ec2 create-vpc --cidr-block 10.0.0.0/16 \
    --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=demo-vpc}]'
{
    "Vpc": {
        "OwnerId": "123456789012",
        "InstanceTenancy": "default",
        "CidrBlockAssociationSet": [
            {
                "AssociationId": "vpc-cidr-assoc-dadd6847c734013f5",
                "CidrBlock": "10.0.0.0/16",
                "CidrBlockState": {
                    "State": "associated"
                }
            }
        ],
        "IsDefault": false,
        "Tags": [ { "Key": "Name", "Value": "demo-vpc" } ],
        "VpcId": "vpc-70b60b71d6b775b56",
        "State": "available",
        "CidrBlock": "10.0.0.0/16",
        "DhcpOptionsId": "default"
    }
}

サブネット2つ(同じ AZ にパブリック用とプライベート用)

$ aws ec2 create-subnet --vpc-id $VPC --cidr-block 10.0.1.0/24 \
    --availability-zone ap-northeast-1a \
    --query 'Subnet.[SubnetId,CidrBlock,AvailabilityZone,AvailableIpAddressCount,MapPublicIpOnLaunch]' --output text
subnet-9efc0c2ac79308a8e	10.0.1.0/24	ap-northeast-1a	251	False

$ aws ec2 create-subnet --vpc-id $VPC --cidr-block 10.0.11.0/24 --availability-zone ap-northeast-1a ...
subnet-e0da279a35999737b	10.0.11.0/24	ap-northeast-1a	251	False

/24 は256個のアドレスですが、使える数(AvailableIpAddressCount)は251でした。 AWS が各サブネットの先頭4つと最後の1つを予約するためで、この計算は後の CIDR の節で確かめます。

IGW・ルートテーブル・NAT を足したあとの表

$ aws ec2 create-internet-gateway --query InternetGateway.InternetGatewayId --output text
igw-58938b2ad0ae7fdee
$ aws ec2 attach-internet-gateway --internet-gateway-id $IGW --vpc-id $VPC
$ aws ec2 create-route --route-table-id $RT_PUB --destination-cidr-block 0.0.0.0/0 --gateway-id $IGW
{
    "Return": true
}
$ aws ec2 associate-route-table --route-table-id $RT_PUB --subnet-id $SUBNET_PUB
{
    "AssociationId": "rtbassoc-a6e55555485c2e263"
}
$ aws ec2 create-nat-gateway --subnet-id $SUBNET_PUB --allocation-id $EIPALLOC ...
nat-639e5cae6c42d344f	subnet-9efc0c2ac79308a8e	available	127.175.24.85	10.69.186.135

$ aws ec2 describe-route-tables --filters Name=vpc-id,Values=$VPC --query '...' --output table
+-----------------------+----------------------------+--------------------------------------------------------+
|  rtb-755f2f9b2f12549fa|                            |  10.0.0.0/16->local                                    |
|  rtb-08ce56f5959264a2e|  subnet-9efc0c2ac79308a8e  |  10.0.0.0/16->local| 0.0.0.0/0->igw-58938b2ad0ae7fdee  |
|  rtb-24311316a2d53d4e6|  subnet-e0da279a35999737b  |  10.0.0.0/16->local| 0.0.0.0/0->nat-639e5cae6c42d344f  |
+-----------------------+----------------------------+--------------------------------------------------------+

1行目が VPC と一緒にできたメインルートテーブル(local だけ)、2行目がパブリック用、3行目がプライベート用です。違いは 0.0.0.0/0 のターゲットが igw- か nat- かの1点だけで、これがパブリックとプライベートの差のすべてです。NAT ゲートウェイの行に出ている 127.175.24.85・10.69.186.135 は moto が作ったダミーの値で、本物の AWS ではサブネットの範囲内のプライベート IP と、割り当てた Elastic IP が入ります。

サブネットがパブリックかどうかを判定するスクリプト

コンソールでサブネットを1つずつ開かなくても、ルートテーブルを読めば判定できます。関連付けの無いサブネットはメインルートテーブルで判定する点が大事です。

import json, subprocess, sys
def aws(*a):
    return json.loads(subprocess.check_output(["aws", "ec2", *a, "--output", "json"]))
vpc = sys.argv[1]
rts = aws("describe-route-tables", "--filters", f"Name=vpc-id,Values={vpc}")["RouteTables"]
main = next(r for r in rts if any(x.get("Main") for x in r["Associations"]))
def kind(rt):
    for r in rt["Routes"]:
        if r.get("DestinationCidrBlock") == "0.0.0.0/0":
            if (r.get("GatewayId") or "").startswith("igw-"):
                return "パブリック(0.0.0.0/0 -> " + r["GatewayId"] + ")"
            if r.get("NatGatewayId"):
                return "プライベート(外向きのみ NAT " + r["NatGatewayId"] + ")"
    return "プライベート(外へ出る経路なし)"
for s in aws("describe-subnets", "--filters", f"Name=vpc-id,Values={vpc}")["Subnets"]:
    rt = next((r for r in rts if any(x.get("SubnetId") == s["SubnetId"] for x in r["Associations"])), main)
    print(s["SubnetId"], s["CidrBlock"], s["AvailabilityZone"], rt["RouteTableId"], kind(rt))
subnet-9efc0c2ac79308a8e 10.0.1.0/24 ap-northeast-1a rtb-08ce56f5959264a2e パブリック(0.0.0.0/0 -> igw-58938b2ad0ae7fdee)
subnet-e0da279a35999737b 10.0.11.0/24 ap-northeast-1a rtb-24311316a2d53d4e6 プライベート(外向きのみ NAT nat-639e5cae6c42d344f)
subnet-66ec7b61d1dc09386 10.0.12.0/24 ap-northeast-1c rtb-755f2f9b2f12549fa プライベート(外へ出る経路なし)

3行目は、関連付けをせずに足したサブネットです。メインルートテーブル(local だけ)が使われ、「分離されたサブネット」として判定されました。

セキュリティグループ(Web から DB だけを許可)

$ aws ec2 authorize-security-group-ingress --group-id $SG_WEB --protocol tcp --port 443 --cidr 0.0.0.0/0 \
    --query 'SecurityGroupRules[].[IsEgress,IpProtocol,FromPort,ToPort,CidrIpv4]' --output text
False	tcp	443	443	0.0.0.0/0
$ aws ec2 authorize-security-group-ingress --group-id $SG_DB --protocol tcp --port 3306 --source-group $SG_WEB ...
False	tcp	3306	3306	sg-3403c37a6a9f100dc
$ aws ec2 describe-security-groups --group-ids $SG_DB --query 'SecurityGroups[0].IpPermissionsEgress'
[ { "IpProtocol": "-1", "IpRanges": [ { "CidrIp": "0.0.0.0/0" } ], ... } ]

DB 側は送信元を IP アドレスではなく「Web のセキュリティグループ」で指定しています。Web サーバーが増えても減っても、DB のルールを書き換えずに済みます。新しいセキュリティグループには、外向き(アウトバウンド)を全部許可するルールが最初から入っていました。セキュリティグループの操作の詳細は、関連記事「AWS CLIでセキュリティグループ設定|ルール追加・削除・確認」で扱っています。

moto と本物の AWS の違い(手元で気づいた点)

  • moto は /29 のサブネットを作成できた(使える数3)。公式ドキュメントでは、サブネットの大きさは /28〜/16 で、/29 は作れない。
  • moto のデフォルト VPC には IGW への経路が無かった。本物のデフォルト VPC は、メインルートテーブルに 0.0.0.0/0 → IGW が入る(公式ドキュメント)。
  • 削除の依存関係の一部(他のセキュリティグループから参照されているグループの削除など)を moto は止めなかった。依存関係の順番は公式ドキュメントに合わせて書いている。

パブリックとプライベートの違いをip netnsで再現(ping・ip route)

この節では、パブリックサブネットのサーバーは外へ出られ、プライベートサブネットのサーバーは出られない理由を、実際のパケットで確かめられます。

moto は API の応答だけを返すので、通信そのものは起きません。 そこで Linux の ip netns で7つの小部屋を作り、VPC と同じ形のネットワークを手元に組みました。インターネット側のアドレスには、文書用に予約された 203.0.113.0/24・198.51.100.0/24 を使っています。

netns の名前 VPC での役 アドレス
t134-pub パブリックサブネットの Web(パブリック IP あり) 10.0.1.10(外からは 198.51.100.10)
t134-pub2 パブリックサブネットだがパブリック IP なし 10.0.1.30
t134-nat NAT ゲートウェイ(Elastic IP あり) 10.0.1.20(外からは 198.51.100.20)
t134-pri プライベートサブネットのサーバー 10.0.11.10
t134-vrt VPC ルーター(サブネットごとのルートテーブル) 10.0.1.1・10.0.11.1
t134-igw IGW(パブリック IP ⇔ プライベート IP の1対1変換) —
t134-inet インターネット上のサーバー 203.0.113.10

「サブネットごとのルートテーブル」は、Linux の ip rule(どの表を引くかの規則)で、入ってきたインターフェイスごとに別の表を引くようにして再現しました。表 101 がパブリック用、表 111 がプライベート用です。

$ ip netns exec t134-vrt ip rule
0:	from all lookup local
1000:	from all iif br-pub lookup 101
1100:	from all iif sub-pri lookup 111
32766:	from all lookup main
32767:	from all lookup default
$ ip netns exec t134-vrt ip route show table 101     # パブリック用
default via 169.254.0.2 dev to-igw
10.0.1.0/24 dev br-pub scope link
10.0.11.0/24 dev sub-pri scope link
$ ip netns exec t134-vrt ip route show table 111     # プライベート用(最初は外への経路なし)
10.0.1.0/24 dev br-pub scope link
10.0.11.0/24 dev sub-pri scope link

サーバー自身の ip route は、パブリックでもプライベートでも「既定の出口はサブネットの .1(VPC ルーター)」で同じです。AWS でも、インスタンスの OS から見た経路はサブネットの種類で変わりません。違いは VPC ルーター側の表にあります。

$ ip netns exec t134-pub ip route
default via 10.0.1.1 dev eth0
10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.10
$ ip netns exec t134-pri ip route
default via 10.0.11.1 dev eth0
10.0.11.0/24 dev eth0 proto kernel scope link src 10.0.11.10

結果1:パブリックは外へ出られる、プライベートは出られない

$ ip netns exec t134-pub ping -c 3 -W 1 203.0.113.10
64 bytes from 203.0.113.10: icmp_seq=1 ttl=62 time=0.428 ms
64 bytes from 203.0.113.10: icmp_seq=2 ttl=62 time=0.076 ms
64 bytes from 203.0.113.10: icmp_seq=3 ttl=62 time=0.060 ms
3 packets transmitted, 3 received, 0% packet loss, time 2051ms

$ ip netns exec t134-pri ping -c 3 -W 1 203.0.113.10
From 10.0.11.1 icmp_seq=1 Destination Net Unreachable
From 10.0.11.1 icmp_seq=2 Destination Net Unreachable
From 10.0.11.1 icmp_seq=3 Destination Net Unreachable
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2030ms

$ ip netns exec t134-pri ping -c 2 -W 1 10.0.1.10      # VPC の中どうしは届く(local の経路)
64 bytes from 10.0.1.10: icmp_seq=1 ttl=63 time=0.032 ms
2 packets transmitted, 2 received, 0% packet loss, time 1020ms

プライベート側は、VPC ルーター(10.0.11.1)が「その宛先への経路が無い」と返しました。VPC の中(10.0.1.10)には届くので、「VPC の中は local で届く、外へは表に行が無いと出られない」がそのまま見えます。AWS の VPC ルーターが同じ ICMP を返すかは公式ドキュメントに書かれていないため、ここでは「どこで止まったか」を見る目的で、Linux の既定の動きのまま示しています。

結果2:外からはパブリック IP にだけ届く

$ ip netns exec t134-inet ping -c 2 -W 1 198.51.100.10     # Web のパブリック IP
64 bytes from 198.51.100.10: icmp_seq=1 ttl=62 time=0.103 ms
2 packets transmitted, 2 received, 0% packet loss, time 1008ms

$ ip netns exec t134-inet ping -c 2 -W 1 10.0.11.10        # プライベート IP あて
ping: connect: Network is unreachable

インターネット側から見ると、10.0.11.10 のようなプライベート IP には経路そのものがありません。プライベートサブネットが外から守られているのは、設定で隠しているからではなく、外から指す宛先が存在しないからです。

結果3:パブリックサブネットでもパブリック IP が無いと出られない

$ ip netns exec t134-pub2 ping -c 2 -W 1 203.0.113.10
2 packets transmitted, 0 received, 100% packet loss, time 1009ms

# VPC ルーター → IGW の間では見える
$ ip netns exec t134-vrt tcpdump -n -i to-igw icmp
IP 10.0.1.30 > 203.0.113.10: ICMP echo request, id 21380, seq 1, length 64
IP 10.0.1.30 > 203.0.113.10: ICMP echo request, id 21380, seq 2, length 64
# インターネット側には1つも届かない
$ ip netns exec t134-inet tcpdump -n -i eth0 icmp
0 packets captured

10.0.1.30 は同じパブリックサブネットにいて、同じルートテーブルで IGW まで行きます。それでも、付け替える先のパブリック IP が無いので、IGW の先へは出られません。 EC2 を「パブリックサブネットに置いたのにインターネットにつながらない」ときは、パブリック IP の自動割り当て(サブネットの MapPublicIpOnLaunch、起動時の設定)を見ます。

結果4:NAT への経路を足すと、プライベートから外へ出られる

プライベート用の表 111 に「0.0.0.0/0 → NAT(10.0.1.20)」を1行足しました。AWS で create-route --nat-gateway-id をするのと同じ操作です。

$ ip netns exec t134-vrt ip route add default via 10.0.1.20 table 111
$ ip netns exec t134-vrt ip route get 203.0.113.10 from 10.0.11.10 iif sub-pri
203.0.113.10 from 10.0.11.10 via 10.0.1.20 dev br-pub table 111
$ ip netns exec t134-pri ping -c 2 -W 1 203.0.113.10
64 bytes from 203.0.113.10: icmp_seq=1 ttl=60 time=0.095 ms
64 bytes from 203.0.113.10: icmp_seq=2 ttl=60 time=0.073 ms
2 packets transmitted, 2 received, 0% packet loss, time 1010ms

同じ1回の ping を、3か所で同時に tcpdump しました。送信元のアドレスが2回付け替わる様子が分かります。

# (1) プライベートのサーバーの中
IP 10.0.11.10 > 203.0.113.10: ICMP echo request, id 21363, seq 1, length 64
IP 203.0.113.10 > 10.0.11.10: ICMP echo reply, id 21363, seq 1, length 64
# (2) VPC ルーター → IGW の間(NAT が自分のプライベート IP に付け替えた)
IP 10.0.1.20 > 203.0.113.10: ICMP echo request, id 21363, seq 1, length 64
IP 203.0.113.10 > 10.0.1.20: ICMP echo reply, id 21363, seq 1, length 64
# (3) インターネット側(IGW が NAT の Elastic IP に付け替えた)
IP 198.51.100.20 > 203.0.113.10: ICMP echo request, id 21363, seq 1, length 64
IP 203.0.113.10 > 198.51.100.20: ICMP echo reply, id 21363, seq 1, length 64

1差はルートテーブルの1行

サーバー側の設定は同じまま、VPC ルーターの表に IGW か NAT の行があるかで、出られる・出られないが変わった。

2パブリック IP が無いと IGW を越えない

同じパブリックサブネットでも、パブリック IP の無い 10.0.1.30 は IGW の手前で止まった。

3外から見えるのは Elastic IP だけ

プライベートのサーバーの通信は、外では NAT の 198.51.100.20 として見える。外部 API に許可 IP を登録するときはこの値。

VPCのCIDRとサブネットの決め方(Python ipaddressで計算)

この節では、VPC とサブネットの IP アドレスの範囲(CIDR)をどう決めればよいかが、計算つきで分かります。

CIDR(サイダー)は「10.0.0.0/16」のように、先頭からのビット数でネットワークの大きさを表す書き方です。 /16 なら先頭16ビットが固定で、残り16ビット分=65,536個のアドレスを持ちます。数字が1増えると大きさは半分になります。

決まり(公式ドキュメント)

  • VPC の IPv4 CIDR は /16(65,536個)〜/28(16個)。RFC 1918 のプライベートアドレス(10.0.0.0/8・172.16.0.0/12・192.168.0.0/16)から取るのが推奨。
  • サブネットも /16〜/28。VPC の範囲の中で、サブネットどうしは重ねられない。
  • 各サブネットの先頭4つと最後の1つは AWS の予約で使えない。
  • 既にある CIDR の大きさは変えられない。足りなくなったら、セカンダリ CIDR を追加する(最初の CIDR は外せない)。
import ipaddress as ip
for p in (16, 18, 20, 22, 24, 26, 27, 28):
    n = ip.ip_network(f"10.0.0.0/{p}")
    print(f"/{p}: 全体 {n.num_addresses:>6}  使える {n.num_addresses-5:>6}  マスク {n.netmask}")
/16: 全体  65536  使える  65531  マスク 255.255.0.0
/18: 全体  16384  使える  16379  マスク 255.255.192.0
/20: 全体   4096  使える   4091  マスク 255.255.240.0
/22: 全体   1024  使える   1019  マスク 255.255.252.0
/24: 全体    256  使える    251  マスク 255.255.255.0
/26: 全体     64  使える     59  マスク 255.255.255.192
/27: 全体     32  使える     27  マスク 255.255.255.224
/28: 全体     16  使える     11  マスク 255.255.255.240

/24 の「使える 251」は、moto の AvailableIpAddressCount(251)とも一致しました。予約される5つは次のとおりです(公式ドキュメントの 10.0.0.0/24 の例を 10.0.1.0/24 に当てはめたもの)。

10.0.1.0    ネットワークアドレス
10.0.1.1    VPC ルーター
10.0.1.2    DNS(VPC の範囲の先頭+2。各サブネットの+2も予約)
10.0.1.3    将来の予約
10.0.1.255  ブロードキャスト(VPC はブロードキャスト非対応のため予約)
65,531個/16 の VPC で使える数1つのサブネットにした場合
16個/16 を /20 に分けた数1つあたり 4,091 使える
11個/28 で使える数いちばん小さいサブネット

3つの AZ × パブリック/プライベートに分ける例

vpc = ip.ip_network("10.0.0.0/16")
subs = list(vpc.subnets(new_prefix=20))
plan = {"public-a": subs[0], "public-c": subs[1], "public-d": subs[2],
        "private-a": subs[4], "private-c": subs[5], "private-d": subs[6]}
16 個: 10.0.0.0/20, 10.0.16.0/20, 10.0.32.0/20, 10.0.48.0/20, 10.0.64.0/20, 10.0.80.0/20 ...
public-a   10.0.0.0/20  使える 4091
public-c   10.0.16.0/20  使える 4091
public-d   10.0.32.0/20  使える 4091
private-a  10.0.64.0/20  使える 4091
private-c  10.0.80.0/20  使える 4091
private-d  10.0.96.0/20  使える 4091
残り: 10 個の /20

パブリックとプライベートの間(10.0.48.0/20)を1つ空けておくと、あとで4つ目の AZ を足しても番号の並びがそろいます。EKS(Kubernetes)や Lambda を VPC で動かすと、Pod や関数の数だけ IP を使うことがあるため、プライベート側は大きめに取ります。

重なりの確認

CIDR でいちばん困るのは「あとでつなぐ相手と重なる」ことです。 VPC ピアリングは重なる CIDR どうしでは作れず、社内ネットワークと VPN でつなぐときも経路が決められなくなります。作る前に、社内・他の VPC・開発 PC の Docker などの範囲と重ならないかを確かめます。

for a, b in [("10.0.0.0/16", "10.0.128.0/17"), ("10.0.0.0/16", "10.1.0.0/16"),
             ("10.0.0.0/16", "10.0.0.0/8"), ("172.31.0.0/16", "172.16.0.0/12"),
             ("172.17.0.0/16", "172.31.0.0/16")]:
    print(a, "と", b, "重なる" if ip.ip_network(a).overlaps(ip.ip_network(b)) else "重ならない")
10.0.0.0/16 と 10.0.128.0/17 重なる
10.0.0.0/16 と 10.1.0.0/16 重ならない
10.0.0.0/16 と 10.0.0.0/8 重なる
172.31.0.0/16 と 172.16.0.0/12 重なる
172.17.0.0/16 と 172.31.0.0/16 重ならない

どの VPC も 10.0.0.0/16 で作ると、あとでつなげなくなります。「VPC ごとに 10.1.0.0/16・10.2.0.0/16…と番号を割り振る表」をチームで1つ持つのが確実です。AWS には、この割り振りを管理する VPC IP Address Manager(IPAM)もあります。なお、Python の is_private は RFC 1918 以外(文書用の 203.0.113.0/24 など)にも True を返したため、RFC 1918 かどうかの判定には使えませんでした。CIDR とサブネットマスクの計算をさらに詳しく知りたいときは、関連記事「CIDR計算・サブネット早見表|/0〜/32一覧とPython計算コード」で扱っています。

セキュリティグループとネットワークACLの違い

この節では、2つのファイアウォールの違いと、ステートフル・ステートレスの差が通信にどう出るのかが、実測で分かります。

公式ドキュメントの比較表を日本語にまとめると次のとおりです。

項目 セキュリティグループ ネットワーク ACL
効く場所 インスタンス(ネットワークインターフェイス) サブネット
ルールの種類 許可だけ 許可と拒否
判定の仕方 すべてのルールを見て決める 番号の小さい順に、最初に合ったもので決める
戻りの通信 自動で許可(ステートフル) 明示的に許可が要る(ステートレス)
既定のクォータ 1インターフェイスに5つ、1グループに入・出それぞれ60ルール 入・出それぞれ20ルール(最大40)

セキュリティグループで絞るもの

サーバーの役割ごとの許可(Web は 443、DB は Web からだけ)

送信元にセキュリティグループを指定できる

ふだんの制御はこちらが中心

ネットワーク ACL で絞るもの

サブネット全体で特定の IP やポートを拒否

拒否のルールが書ける唯一の場所

戻りの通信(エフェメラルポート)も書く

実測:ステートフル(SG)は戻りを書かなくても通る

ip netns の Web サーバー(t134-pub)で 8080 番の HTTP サーバーを起動し、セキュリティグループの代わりに「受信は既定で拒否、8080 と接続済みの戻りだけ許可」のルールを入れました。

ルールなし     8080 → code=200 time=0.003392
ルールなし     22   → curl: (7) Failed to connect to 198.51.100.10 port 22 after 0 ms: Couldn't connect to server
SG 相当あり   8080 → code=200 time=0.002363
SG 相当あり   22   → curl: (28) Connection timed out after 3001 milliseconds

許可していない 22 番は、「接続を拒否された(すぐ返る)」から「時間切れ(3秒待って失敗)」に変わりました。 AWS のセキュリティグループも、許可していない通信には何も返さず捨てるため、接続できないときに「タイムアウトする」のは、セキュリティグループかネットワーク ACL で止まっている合図です。「Connection refused」がすぐ返るなら、通信はサーバーまで届いていて、そのポートでプログラムが待ち受けていません。

実測:ステートレス(NACL)は戻りのポートを書かないと通らない

次に、パブリックサブネットの入口(VPC ルーター)に NACL 相当のルールを入れました。受信は「8080 を許可」、送信は「443 を許可、それ以外は拒否」です。一見、Web サーバーへの 8080 は通りそうです。

NACL 送信が 443 だけ        → curl: (28) Connection timed out after 3002 milliseconds
  4   240 DROP  /* * deny */                         ← 応答のパケットが捨てられた
送信に 1024-65535 を足した  → code=200 time=0.002515
  6   527 ACCEPT tcp dpts:1024:65535 /* 110 allow tcp 1024-65535 */

Web サーバーからの応答は、宛先がクライアント側の一時的なポート(エフェメラルポート)になります。手元のクライアントの範囲は net.ipv4.ip_local_port_range = 32768 60999 でした。NACL は戻りを覚えていないので、この範囲を送信側で許可しないと、応答が捨てられて時間切れになります。 公式ドキュメントは、クライアントの OS によって範囲が違う(多くの Linux は 32768-61000、Windows Server 2008 以降は 49152-65535、NAT ゲートウェイと ELB は 1024-65535)ことから、1024-65535 を開け、拒否したいポートはそれより前の番号で拒否する方法を示しています。

同じ NACL を付けたまま、プライベートのサーバーから NAT 経由で外へ HTTP を送ると、これも時間切れになりました。NAT はパブリックサブネットにいるので、プライベートのサーバーの通信もパブリックサブネットの NACL を通ります。 送信側に宛先 8080、受信側に 1024-65535 を足すと、応答が戻ってくるようになりました。

デフォルトVPCとは(そのまま使ってよいか)

この節では、アカウントに最初からある VPC が何で、どう扱えばよいかが分かります。

AWS アカウントには、リージョンごとにデフォルト VPC が1つ用意されていて、作ってすぐ EC2 を起動して接続できるように設定されています。 公式ドキュメントが挙げる中身は次のとおりです。

  • 172.31.0.0/16 の VPC(最大65,536個のプライベート IPv4 アドレス)
  • AZ ごとに /20 のデフォルトサブネット(1つあたり4,096個、うち数個は予約)
  • インターネットゲートウェイをアタッチ
  • メインルートテーブルに 0.0.0.0/0 → IGW の経路
  • デフォルトのセキュリティグループ、デフォルトのネットワーク ACL、デフォルトの DHCP オプションセット

moto のデフォルト VPC も、AZ ごとに /20 のサブネットが3つ並び、それぞれ使える数は 4,091、MapPublicIpOnLaunch は True でした。

|  ap-northeast-1a |  172.31.0.0/20   |  True |  4091 |
|  ap-northeast-1c |  172.31.16.0/20  |  True |  4091 |
|  ap-northeast-1d |  172.31.32.0/20  |  True |  4091 |

デフォルト VPC は、すべてのサブネットがパブリックです。 学習や短い検証には便利ですが、DB や社内向けのサーバーを置く本番の環境には、プライベートサブネットを持つ VPC を別に作るのが一般的です。また、デフォルト VPC の範囲は 172.31.0.0/16 なので、他の VPC や社内網とつなぐ予定があるなら重なりに注意します。デフォルト VPC は削除できますが、ロードバランサーや RDS の作成時にデフォルト VPC を前提にする画面もあるため、消す前にチームで使い道を決めておきます。

VPCエンドポイント・ピアリング・Transit Gatewayの概要

この節では、VPC を「AWS のサービス」「他の VPC」「社内網」とつなぐ部品の違いが分かります。

VPC エンドポイント(AWS のサービスへ、インターネットを通らずに)

  • ゲートウェイエンドポイント:S3 と DynamoDB 用。ルートテーブルに「S3 のプレフィックスリスト → vpce-…」の行が入る。追加料金なし(公式ドキュメント)。
  • インターフェイスエンドポイント(PrivateLink):多くの AWS サービス用。サブネットにネットワークインターフェイスが作られ、時間とデータ量で課金される。

プライベートサブネットから S3 へ大量のデータを送るとき、NAT ゲートウェイ経由だとデータ処理の料金がかかります。ゲートウェイエンドポイントを付ければ、S3 あての通信は NAT を通らなくなります。

VPC ピアリングと Transit Gateway

項目 VPC ピアリング Transit Gateway
つなぎ方 2つの VPC を1対1 中央のハブに各 VPC・VPN・Direct Connect をつなぐ
推移的なルーティング 不可(A-B・A-C があっても B から C へは行けない) ハブ経由で行ける(ルートテーブルで制御)
CIDR の重なり 重なる VPC どうしは作れない 重なると経路を決められない
料金の形 接続の時間料金なし。AZ をまたぐデータ転送に料金 アタッチメントの時間料金+データ処理料金
向いている規模 VPC が数個 VPC が多い、社内網ともつなぐ

ピアリングの公式ドキュメントには、相手の VPC の IGW・NAT・VPN・Direct Connect・ゲートウェイエンドポイントを経由して外へ出ることもできない(edge to edge routing の不可)と書かれています。「VPC A の NAT を VPC B からも使って節約する」構成は、ピアリングではできません。

VPCの料金の考え方(2026年10月29日時点)

この節では、VPC で何にお金がかかり、何が無料なのかが分かります。

公式ドキュメントは「VPC の利用に追加料金はかからない。ただし NAT ゲートウェイ・IPAM・トラフィックミラーリング・Reachability Analyzer・Network Access Analyzer などの部品には料金がかかる」と書いています。 VPC・サブネット・ルートテーブル・IGW・セキュリティグループ・ネットワーク ACL を作るだけなら料金はかかりません。

部品 料金の形 公式ページの値(2026年10月29日時点)
NAT ゲートウェイ 時間+処理したデータ量 料金ページの例(米国東部・オハイオ):1時間 0.045 USD、1GB 0.045 USD。リージョン型は AZ ごとに時間料金
パブリック IPv4 アドレス 1つあたりの時間 使用中・アイドルとも 1時間 0.005 USD(商用リージョン共通)
ゲートウェイエンドポイント なし 追加料金なし(S3・DynamoDB)
インターフェイスエンドポイント AZ ごとの時間+データ量 データ処理は最初の 1PB まで 1GB 0.01 USD(リージョン内の合計)
VPC ピアリング データ転送 同じリージョンで AZ をまたぐと、送受信それぞれ 1GB 0.01 USD
Transit Gateway アタッチメントの時間+データ処理 料金ページの例(米国東部・オハイオ):VPC アタッチメント 1時間 0.05 USD、1GB 0.02 USD

料金はリージョンで違い、NAT ゲートウェイ・インターフェイスエンドポイント・Transit Gateway の東京リージョン(ap-northeast-1)の値は、料金ページでリージョンを選んだときに表示されます。この表の米国東部の値は、料金ページに載っている計算例の値です。見積もりは、料金ページでリージョンを「アジアパシフィック(東京)」に切り替えるか、AWS Pricing Calculator で行います。

費用が大きくなりやすいところ

  • NAT ゲートウェイは、使っていなくても時間料金がかかる。 AZ ごとに置くと、その数だけかかる。夜間に止められる開発環境では、NAT を置かない構成や VPC エンドポイントの利用を検討する。
  • NAT を通るデータ量にも料金がかかる。 S3 への大量転送はゲートウェイエンドポイント(無料)に逃がす。
  • パブリック IPv4 アドレスは、使用中でも有料。 公式ドキュメントによれば、RFC 1918 のプライベート IPv4 には料金がかからない。EC2 の無料利用枠では、パブリック IPv4 の750時間分が無料。

よくあるエラーとつまずき(原文つき)

この節では、VPC を作るとき・使うときに出るエラーの原文と、原因・直し方が分かります。

出た文言・症状 原因 直し方
InvalidSubnet.Conflict:The CIDR '10.0.1.128/25' conflicts with another subnet 既にあるサブネットと範囲が重なる 重ならない範囲を選ぶ(計算は Python の overlaps で確かめる)
InvalidSubnet.Range:The CIDR '10.1.0.0/24' is invalid. サブネットが VPC の範囲の外 VPC の CIDR の内側で切る。足りなければセカンダリ CIDR を追加
InvalidVpc.Range:The CIDR '10.0.0.0/15' is invalid. VPC の大きさが /16〜/28 の外(/15・/29 で出た) /16〜/28 にする
DependencyViolation:The vpc '…' has dependencies and cannot be deleted. 中にサブネット・IGW・NAT などが残っている 作った順の逆に消す(次の手順)
DependencyViolation:igw-… is being utilized by vpc-… VPC にアタッチしたまま IGW を消そうとした detach-internet-gateway してから削除
InvalidPermission.Duplicate:The specified rule already exists 同じルールをもう一度足した describe-security-groups で今のルールを見てから足す
InvalidInternetGatewayID.NotFound 経路のターゲットに存在しない IGW の ID ID の写し間違い・別リージョンを確かめる
ping・curl が時間切れになる SG・NACL で捨てられている、またはパブリック IP・経路が無い 経路→パブリック IP→SG→NACL の順に見る

エラーの文言は moto 5.1.22 が返したものです。本物の AWS も同じエラーコード(InvalidSubnet.Conflict など)を返しますが、メッセージの細かい文面は違うことがあります。

削除の順番(依存関係の逆)

1 NAT ゲートウェイを削除      delete-nat-gateway
2 Elastic IP を解放           release-address
3 IGW をデタッチして削除      detach-internet-gateway → delete-internet-gateway
4 サブネットを削除            delete-subnet
5 ルートテーブルの関連付けを外して削除   disassociate-route-table → delete-route-table
6 セキュリティグループを削除(参照している側から)   delete-security-group
7 VPC を削除                  delete-vpc

手元ではこの順で消し、最後の delete-vpc が成功して、残ったのはデフォルト VPC だけになりました。消し忘れると料金が続くのは NAT ゲートウェイと Elastic IP(パブリック IPv4)です。

つながらないときのチェック

  • 1サブネットのルートテーブルを見る関連付けが無ければメインルートテーブルが使われる。0.0.0.0/0 のターゲットが igw- か nat- か
  • 2パブリック IP が付いているかパブリックサブネットでもパブリック IP が無いと IGW を越えない(手元の再現でも止まった)
  • 3セキュリティグループの受信ルール時間切れなら SG か NACL を疑う。Connection refused がすぐ返るなら届いている
  • 4NACL の戻りのポート送信側・受信側に 1024-65535 が無いと応答が捨てられる。NAT のいるサブネットの NACL も通る
  • 5NAT ゲートウェイの置き場所ゾーン型はパブリックサブネットに置く。プライベートサブネットに置くと外へ出られない
  • 6OS の中のファイアウォールAWS 側が正しくても、OS の firewalld・ufw・Windows ファイアウォールで止まることがある

原因の切り分けの考え方は、関連記事「穴だらけにしない!AWSネットワークセキュリティの定石!」も参考になります。

VPC構成の判断表

この節では、作りたいものに対して、どのサブネットと部品を選べばよいかが分かります。

  1. 1インターネットから直接アクセスされる → パブリックサブネットロードバランサー・NAT ゲートウェイ(ゾーン型)・踏み台。パブリック IP が要る
  2. 2外へは出るが、外からは入られたくない → プライベート+NATアプリサーバー・バッチ。OS の更新や外部 API の呼び出し
  3. 3AWS のサービスとだけ話す → プライベート+VPC エンドポイントS3・DynamoDB はゲートウェイ型(無料)。NAT の費用を減らせる
  4. 4VPC の中とだけ話す → 分離されたサブネットDB(RDS)など。外への経路を持たない
  5. 5社内ネットワークとつなぐ → VPN または Direct ConnectCIDR を社内と重ねないことが前提
  6. 6他の VPC とつなぐ → 数個ならピアリング、多いなら Transit Gatewayピアリングは推移的なルーティング不可
場面 おすすめの形 理由
AWS の学習・短い検証 デフォルト VPC か、パブリックサブネット1つ NAT が要らず、料金がかかる部品が少ない
小さな Web サービス 2AZ × パブリック/プライベート、NAT は1つ 可用性と費用の釣り合い。NAT の AZ が止まると外へ出られない点は受け入れる
止められない本番 3AZ × パブリック/プライベート、NAT は AZ ごと(またはリージョン型) 1つの AZ の障害で外向きの通信が止まらない
S3 を大量に読み書きする ゲートウェイエンドポイントを追加 NAT のデータ処理料金がかからない
サーバーに SSH したい 踏み台より Session Manager 受信ポートを開けずに済み、プライベートのまま接続できる
VPC が今後も増える CIDR の割り振り表を先に作る(または IPAM) あとから CIDR は変えられず、重なるとつなげない

プライベートサブネットのサーバーへ、受信ポートを開けずに入る方法は、関連記事「Session ManagerでEC2に接続する方法|SSH鍵なしの手順」で扱っています。グローバル IP とプライベート IP、NAT の基本は、関連記事「グローバルIPの確認方法|コマンド・プライベートIPとの違いとNATを実演」で扱っています。

よくある質問

Q. VPCとは何ですか? A. AWS の中に作る、論理的に切り離された自分専用の仮想ネットワークです。IP アドレスの範囲・サブネット・経路・出入り口・通してよい通信を自分で決め、その中に EC2 や RDS などを置きます。

Q. VPC とサブネットの違いは何ですか? A. VPC は全体の敷地(例:10.0.0.0/16)、サブネットはそれを小分けした部屋(例:10.0.1.0/24)です。VPC はリージョン単位、サブネットは AZ 単位で、サーバーはサブネットに置きます。

Q. パブリックサブネットとプライベートサブネットはどう作り分けますか? A. 作るときの設定は同じです。作ったあと、関連付けるルートテーブルに「0.0.0.0/0 → インターネットゲートウェイ」があればパブリック、無ければプライベートになります。

Q. NAT ゲートウェイは必ず要りますか? A. プライベートサブネットのサーバーがインターネットへ出る必要があるときだけ要ります。AWS のサービスとだけ話すなら VPC エンドポイントで代わりになることがあり、外へ一切出ないなら要りません。

Q. VPC の料金はいくらですか? A. VPC 自体の利用に追加料金はありません。NAT ゲートウェイ(時間+データ量)、パブリック IPv4 アドレス(1時間 0.005 USD)、インターフェイスエンドポイント、Transit Gateway などの部品に料金がかかります(2026年10月29日時点の公式ページ)。

Q. VPC の CIDR はどれくらいの大きさにすればよいですか? A. 迷ったら /16 を取り、AZ と役割ごとに /20〜/24 に分けます。既にある CIDR の大きさは変えられないため、小さく作って困るより大きめが安全です。他の VPC や社内網と重ならない範囲を選びます。

Q. サブネットで使える IP アドレスが5つ少ないのはなぜですか? A. AWS が各サブネットの先頭4つ(ネットワークアドレス・VPC ルーター・DNS・将来用)と最後の1つ(ブロードキャスト)を予約しているためです。/24 なら 256−5=251 個です。

Q. セキュリティグループとネットワーク ACL はどちらを使えばよいですか? A. ふだんの制御はセキュリティグループで行います。ネットワーク ACL は、サブネット全体で特定の IP やポートを拒否したいときに足します。NACL は戻りの通信も書く必要があり、エフェメラルポート(1024-65535)を忘れると通信が時間切れになります。

Q. デフォルト VPC は削除してもよいですか? A. 削除できますが、デフォルト VPC を前提にしたサービスの画面や、使っている人がいないかを先に確かめます。削除したあとでも、新しいデフォルト VPC を作り直す操作が用意されています。

Q. EC2 をパブリックサブネットに置いたのにインターネットにつながりません。 A. パブリック IP(または Elastic IP)が付いているか、サブネットのルートテーブルに IGW への経路があるか、セキュリティグループと NACL を順に見ます。手元の再現でも、パブリック IP の無いサーバーだけは IGW の先へ出られませんでした。

Q. VPC ピアリングで3つの VPC を順につなげば、端から端まで通信できますか? A. できません。ピアリングは推移的なルーティングに対応しておらず、A-B と A-C があっても B から C へは行けません。B-C にもピアリングを作るか、Transit Gateway を使います。

Q. VPC を作る練習を、料金をかけずにできますか? A. VPC・サブネット・ルートテーブル・IGW・セキュリティグループは作るだけなら料金がかかりません。NAT ゲートウェイと Elastic IP は時間で課金されるため、練習のあとは削除します。この記事のように、moto を 127.0.0.1 で動かせば AWS に接続せずに AWS CLI の操作を試せます。

まとめ

  • Amazon VPC は、AWS の中に作る自分専用の仮想ネットワーク。VPC はリージョン単位、サブネットは AZ 単位。
  • パブリックとプライベートは、サブネットのルートテーブルに「0.0.0.0/0 → IGW」があるかで決まる。手元の再現でも、差はルーターの表の1行だった。
  • IGW は双方向で、パブリック IP と組で働く。NAT ゲートウェイは中から外への片道で、外からは入られない。tcpdump では送信元が 10.0.11.10 → 10.0.1.20 → 198.51.100.20 と2回付け替わった。
  • CIDR は /16〜/28。各サブネットの5つは予約。大きさはあとから変えられず、他の VPC・社内網と重ねない。
  • セキュリティグループはステートフル、NACL はステートレス。NACL はエフェメラルポートを書かないと応答が捨てられ、時間切れになる。料金は VPC 自体は無料で、NAT ゲートウェイとパブリック IPv4 が主な費用。

参考・出典

確認日はいずれも 2026年10月29日です。

  • AWS「What is Amazon VPC?」:https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html
  • AWS「VPC CIDR blocks」:https://docs.aws.amazon.com/vpc/latest/userguide/vpc-cidr-blocks.html
  • AWS「Subnet CIDR blocks」:https://docs.aws.amazon.com/vpc/latest/userguide/subnet-sizing.html
  • AWS「Subnets for your VPC」(Subnet types):https://docs.aws.amazon.com/vpc/latest/userguide/configure-subnets.html
  • AWS「Default VPC components」:https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc-components.html
  • AWS「NAT gateways」:https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html
  • AWS「Regional NAT gateways」:https://docs.aws.amazon.com/vpc/latest/userguide/nat-gateways-regional.html
  • AWS「Infrastructure security in Amazon VPC」(セキュリティグループとネットワーク ACL の比較):https://docs.aws.amazon.com/vpc/latest/userguide/infrastructure-security.html
  • AWS「Custom network ACLs」(Ephemeral ports):https://docs.aws.amazon.com/vpc/latest/userguide/custom-network-acl.html
  • AWS「Amazon VPC quotas」:https://docs.aws.amazon.com/vpc/latest/userguide/amazon-vpc-limits.html
  • AWS「Gateway endpoints」:https://docs.aws.amazon.com/vpc/latest/privatelink/gateway-endpoints.html
  • AWS「VPC peering basics」:https://docs.aws.amazon.com/vpc/latest/peering/vpc-peering-basics.html
  • AWS「Amazon VPC pricing」:https://aws.amazon.com/vpc/pricing/
  • AWS「AWS PrivateLink pricing」:https://aws.amazon.com/privatelink/pricing/
  • AWS「AWS Transit Gateway pricing」:https://aws.amazon.com/transit-gateway/pricing/
  • moto「Non-Python SDK’s / Server Mode」:https://docs.getmoto.org/en/latest/docs/server_mode.html
  • Google Cloud「VPC ネットワークの概要」:https://docs.cloud.google.com/vpc/docs/overview?hl=ja
  • Python「ipaddress — IPv4/IPv6 manipulation library」:https://docs.python.org/3/library/ipaddress.html
  • IETF「RFC 1918 Address Allocation for Private Internets」:https://www.rfc-editor.org/rfc/rfc1918
  • IETF「RFC 5737 IPv4 Address Blocks Reserved for Documentation」:https://www.rfc-editor.org/rfc/rfc5737

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「VPCとは?AWSのサブネット・IGW・NATの関係を手元で再現」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ
参加受付中

AI駆動開発、 無料セミナー