VPC via SDK Basics
Eight short examples that build a real two-tier VPC - one public subnet, one private - entirely from code, then tear it down cleanly.
Busca en todas las páginas de la documentación
Eight short examples that build a real two-tier VPC - one public subnet, one private - entirely from code, then tear it down cleanly.
Each example shows the same operation in both Python (boto3) and TypeScript (AWS SDK for JavaScript v3), so the mechanics translate one to one. Run them in order; later steps reuse ids from earlier ones.
pip install boto3 (boto3 1.43.x, Python 3.10+). TypeScript: npm install @aws-sdk/client-ec2 (Node.js 18+).aws configure, environment variables, or an IAM role with ec2:*Vpc*, ec2:*Subnet*, ec2:*RouteTable*, ec2:*Route, ec2:*InternetGateway*, and ec2:CreateTags.CreateVpc allocates only the CIDR container - the outermost object everything else references.
# --- Python (boto3) ---
import boto3
ec2 = boto3.client("ec2", region_name="us-east-1")
resp = ec2.create_vpc(
CidrBlock="10.0.0.0/16",
TagSpecifications=[{"ResourceType": "vpc",
"Tags": [{"Key": "Name", "Value": "demo-vpc"}]}],
)
vpc_id = resp["Vpc"]["VpcId"]
print(vpc_id)// --- TypeScript (AWS SDK v3) ---
import { EC2Client, CreateVpcCommand } from "@aws-sdk/client-ec2";
const ec2 = new EC2Client({ region: "us-east-1" });
const resp = await ec2.send(new CreateVpcCommand({
CidrBlock: "10.0.0.0/16",
TagSpecifications: [{ ResourceType: "vpc",
Tags: [{ Key: "Name", Value: "demo-vpc" }] }],
}));
const vpcId = resp.Vpc?.VpcId;
console.log(vpcId);/16 gives 65,536 addresses; size the block for growth since you cannot shrink it later.10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16) that will not overlap networks you might peer with.TagSpecifications tags the VPC at creation so it is never anonymous.VpcId feeds every following call.Custom VPCs have enableDnsHostnames off by default; flip it so instances get public DNS names.
# --- Python (boto3) ---
ec2.modify_vpc_attribute(VpcId=vpc_id, EnableDnsHostnames={"Value": True})// --- TypeScript (AWS SDK v3) ---
import { ModifyVpcAttributeCommand } from "@aws-sdk/client-ec2";
await ec2.send(new ModifyVpcAttributeCommand({
VpcId: vpcId,
EnableDnsHostnames: { Value: true },
}));enableDnsSupport is already on by default; only enableDnsHostnames needs flipping.ModifyVpcAttribute call.ec2-...compute.amazonaws.com name.CreateSubnet carves a smaller CIDR out of the VPC and pins it to one Availability Zone.
# --- Python (boto3) ---
public = ec2.create_subnet(
VpcId=vpc_id, CidrBlock="10.0.1.0/24", AvailabilityZone="us-east-1a",
TagSpecifications=[{"ResourceType": "subnet",
"Tags": [{"Key": "Name", "Value": "demo-public-1a"}]}],
)
private = ec2.create_subnet(
VpcId=vpc_id, CidrBlock="10.0.2.0/24", AvailabilityZone="us-east-1b",
TagSpecifications=[{"ResourceType": "subnet",
"Tags": [{"Key": "Name", "Value": "demo-private-1b"}]}],
)
public_id = public["Subnet"]["SubnetId"]
private_id = private["Subnet"]["SubnetId"]// --- TypeScript (AWS SDK v3) ---
import { CreateSubnetCommand } from "@aws-sdk/client-ec2";
const pub = await ec2.send(new CreateSubnetCommand({
VpcId: vpcId, CidrBlock: "10.0.1.0/24", AvailabilityZone: "us-east-1a",
TagSpecifications: [{ ResourceType: "subnet",
Tags: [{ Key: "Name", Value: "demo-public-1a" }] }],
}));
const priv = await ec2.send(new CreateSubnetCommand({
VpcId: vpcId, CidrBlock: "10.0.2.0/24", AvailabilityZone: "us-east-1b",
TagSpecifications: [{ ResourceType: "subnet",
Tags: [{ Key: "Name", Value: "demo-private-1b" }] }],
}));
const publicId = pub.Subnet?.SubnetId;
const privateId = priv.Subnet?.SubnetId;/24 yields 251 usable IPs.Set MapPublicIpOnLaunch so instances in the public subnet get a public IPv4 automatically.
# --- Python (boto3) ---
ec2.modify_subnet_attribute(
SubnetId=public_id, MapPublicIpOnLaunch={"Value": True},
)// --- TypeScript (AWS SDK v3) ---
import { ModifySubnetAttributeCommand } from "@aws-sdk/client-ec2";
await ec2.send(new ModifySubnetAttributeCommand({
SubnetId: publicId, MapPublicIpOnLaunch: { Value: true },
}));AssociatePublicIpAddress network-interface flag.An internet gateway is created independently, then attached to the VPC.
# --- Python (boto3) ---
igw = ec2.create_internet_gateway(
TagSpecifications=[{"ResourceType": "internet-gateway",
"Tags": [{"Key": "Name", "Value": "demo-igw"}]}],
)
igw_id = igw["InternetGateway"]["InternetGatewayId"]
ec2.attach_internet_gateway(InternetGatewayId=igw_id, VpcId=vpc_id)// --- TypeScript (AWS SDK v3) ---
import { CreateInternetGatewayCommand, AttachInternetGatewayCommand } from "@aws-sdk/client-ec2";
const igw = await ec2.send(new CreateInternetGatewayCommand({
TagSpecifications: [{ ResourceType: "internet-gateway",
Tags: [{ Key: "Name", Value: "demo-igw" }] }],
}));
const igwId = igw.InternetGateway?.InternetGatewayId;
await ec2.send(new AttachInternetGatewayCommand({ InternetGatewayId: igwId, VpcId: vpcId }));AttachInternetGateway.DetachInternetGateway first.A new route table plus a 0.0.0.0/0 route to the gateway is what makes a subnet public.
# --- Python (boto3) ---
rt = ec2.create_route_table(VpcId=vpc_id)
rt_id = rt["RouteTable"]["RouteTableId"]
ec2.create_route(
RouteTableId=rt_id, DestinationCidrBlock="0.0.0.0/0", GatewayId=igw_id,
)
ec2.associate_route_table(RouteTableId=rt_id, SubnetId=public_id)// --- TypeScript (AWS SDK v3) ---
import { CreateRouteTableCommand, CreateRouteCommand, AssociateRouteTableCommand } from "@aws-sdk/client-ec2";
const rt = await ec2.send(new CreateRouteTableCommand({ VpcId: vpcId }));
const rtId = rt.RouteTable?.RouteTableId;
await ec2.send(new CreateRouteCommand({
RouteTableId: rtId, DestinationCidrBlock: "0.0.0.0/0", GatewayId: igwId,
}));
await ec2.send(new AssociateRouteTableCommand({ RouteTableId: rtId, SubnetId: publicId }));CreateRoute adds the default route; GatewayId is the internet gateway id.AssociateRouteTable is the step that actually makes the subnet public.local) exists automatically; never add it yourself.Confirm your wiring by describing subnets and checking their attributes.
# --- Python (boto3) ---
resp = ec2.describe_subnets(
Filters=[{"Name": "vpc-id", "Values": [vpc_id]}],
)
for s in resp["Subnets"]:
print(s["SubnetId"], s["CidrBlock"],
s["AvailabilityZone"], s["MapPublicIpOnLaunch"])// --- TypeScript (AWS SDK v3) ---
import { DescribeSubnetsCommand } from "@aws-sdk/client-ec2";
const resp = await ec2.send(new DescribeSubnetsCommand({
Filters: [{ Name: "vpc-id", Values: [vpcId!] }],
}));
for (const s of resp.Subnets ?? []) {
console.log(s.SubnetId, s.CidrBlock, s.AvailabilityZone, s.MapPublicIpOnLaunch);
}vpc-id to scope the results to your VPC.MapPublicIpOnLaunch should be true on the public subnet and false on the private one.AvailableIpAddressCount tells you how much room is left in each subnet.DescribeRouteTables similarly to confirm the 0.0.0.0/0 route.Delete dependents before the VPC, or the final delete fails.
# --- Python (boto3) ---
ec2.disassociate_route_table # (do via the association id from DescribeRouteTables)
ec2.delete_route_table(RouteTableId=rt_id)
ec2.detach_internet_gateway(InternetGatewayId=igw_id, VpcId=vpc_id)
ec2.delete_internet_gateway(InternetGatewayId=igw_id)
ec2.delete_subnet(SubnetId=public_id)
ec2.delete_subnet(SubnetId=private_id)
ec2.delete_vpc(VpcId=vpc_id)// --- TypeScript (AWS SDK v3) ---
import {
DeleteRouteTableCommand, DetachInternetGatewayCommand,
DeleteInternetGatewayCommand, DeleteSubnetCommand, DeleteVpcCommand,
} from "@aws-sdk/client-ec2";
await ec2.send(new DeleteRouteTableCommand({ RouteTableId: rtId }));
await ec2.send(new DetachInternetGatewayCommand({ InternetGatewayId: igwId, VpcId: vpcId }));
await ec2.send(new DeleteInternetGatewayCommand({ InternetGatewayId: igwId }));
await ec2.send(new DeleteSubnetCommand({ SubnetId: publicId }));
await ec2.send(new DeleteSubnetCommand({ SubnetId: privateId }));
await ec2.send(new DeleteVpcCommand({ VpcId: vpcId }));Related: VPC via SDK Best Practices - a CIDR plan and tagging scheme to apply to the resources above.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última actualización: 23 jul 2026