aws-dualstack-ec2
AWS DUALSTACK EC2.
CLI-only workflow. Updated 2026-03-23.
[ variables ]
-------------
```sh
export REGION="${REGION:-us-east-1}"
export TAG="dualstack"
export VPC_CIDR="10.10.0.0/24"
export SUBNET_CIDR_V4="10.10.0.0/26"
export AZ="$(aws ec2 describe-availability-zones \
--region "${REGION}" \
--filters Name=state,Values=available \
--query 'AvailabilityZones[0].ZoneName' \
--output text)"
```
[ dualstack vpc ]
-----------------
```sh
export VPCID="$(aws ec2 create-vpc \
--region "${REGION}" \
--cidr-block "${VPC_CIDR}" \
--amazon-provided-ipv6-cidr-block \
--query 'Vpc.VpcId' \
--output text)"
aws ec2 create-tags \
--region "${REGION}" \
--resources "${VPCID}" \
--tags Key=Name,Value="${TAG}"
aws ec2 modify-vpc-attribute \
--region "${REGION}" \
--vpc-id "${VPCID}" \
--enable-dns-support '{"Value":true}'
aws ec2 modify-vpc-attribute \
--region "${REGION}" \
--vpc-id "${VPCID}" \
--enable-dns-hostnames '{"Value":true}'
```
[ internet gateway ]
--------------------
```sh
export IGW="$(aws ec2 create-internet-gateway \
--region "${REGION}" \
--query 'InternetGateway.InternetGatewayId' \
--output text)"
aws ec2 create-tags \
--region "${REGION}" \
--resources "${IGW}" \
--tags Key=Name,Value="${TAG}"
aws ec2 attach-internet-gateway \
--region "${REGION}" \
--vpc-id "${VPCID}" \
--internet-gateway-id "${IGW}"
```
[ subnet ]
----------
```sh
export V6CIDR="$(aws ec2 describe-vpcs \
--region "${REGION}" \
--vpc-ids "${VPCID}" \
--query 'Vpcs[0].Ipv6CidrBlockAssociationSet[0].Ipv6CidrBlock' \
--output text)"
export SUBNET_CIDR_V6="${V6CIDR%/56}/64"
export SUBNET="$(aws ec2 create-subnet \
--region "${REGION}" \
--vpc-id "${VPCID}" \
--cidr-block "${SUBNET_CIDR_V4}" \
--ipv6-cidr-block "${SUBNET_CIDR_V6}" \
--availability-zone "${AZ}" \
--query 'Subnet.SubnetId' \
--output text)"
aws ec2 create-tags \
--region "${REGION}" \
--resources "${SUBNET}" \
--tags Key=Name,Value="${TAG}"
aws ec2 modify-subnet-attribute \
--region "${REGION}" \
--subnet-id "${SUBNET}" \
--assign-ipv6-address-on-creation
aws ec2 modify-subnet-attribute \
--region "${REGION}" \
--subnet-id "${SUBNET}" \
--map-public-ip-on-launch
```
[ route table ]
---------------
```sh
export RTB="$(aws ec2 create-route-table \
--region "${REGION}" \
--vpc-id "${VPCID}" \
--query 'RouteTable.RouteTableId' \
--output text)"
aws ec2 create-tags \
--region "${REGION}" \
--resources "${RTB}" \
--tags Key=Name,Value="${TAG}"
aws ec2 associate-route-table \
--region "${REGION}" \
--route-table-id "${RTB}" \
--subnet-id "${SUBNET}" \
--query 'AssociationId' \
--output text
aws ec2 create-route \
--region "${REGION}" \
--route-table-id "${RTB}" \
--destination-cidr-block 0.0.0.0/0 \
--gateway-id "${IGW}"
aws ec2 create-route \
--region "${REGION}" \
--route-table-id "${RTB}" \
--destination-ipv6-cidr-block ::/0 \
--gateway-id "${IGW}"
```
[ security group ]
------------------
```sh
export SG="$(aws ec2 create-security-group \
--region "${REGION}" \
--group-name "${TAG}" \
--description "Default security group for ${TAG} instances" \
--vpc-id "${VPCID}" \
--query 'GroupId' \
--output text)"
aws ec2 create-tags \
--region "${REGION}" \
--resources "${SG}" \
--tags Key=Name,Value="${TAG}"
aws ec2 authorize-security-group-ingress \
--region "${REGION}" \
--group-id "${SG}" \
--ip-permissions \
'[{"IpProtocol":"-1","IpRanges":[{"CidrIp":"0.0.0.0/0"}],"Ipv6Ranges":[{"CidrIpv6":"::/0"}]}]'
```
[ launch ]
----------
```sh
export AMI="resolve:ssm:/aws/service/ami-amazon-linux-latest/\
al2023-ami-kernel-default-x86_64"
export INSTANCE_ID="$(aws ec2 run-instances \
--region "${REGION}" \
--image-id "${AMI}" \
--instance-type t3.micro \
--count 1 \
--security-group-ids "${SG}" \
--subnet-id "${SUBNET}" \
--query 'Instances[0].InstanceId' \
--output text)"
aws ec2 wait instance-running \
--region "${REGION}" \
--instance-ids "${INSTANCE_ID}"
export PUBLIC_DNS="$(aws ec2 describe-instances \
--region "${REGION}" \
--instance-ids "${INSTANCE_ID}" \
--query 'Reservations[0].Instances[0].PublicDnsName' \
--output text)"
export PUBLIC_IPV4="$(aws ec2 describe-instances \
--region "${REGION}" \
--instance-ids "${INSTANCE_ID}" \
--query 'Reservations[0].Instances[0].PublicIpAddress' \
--output text)"
export PUBLIC_IPV6="$(aws ec2 describe-instances \
--region "${REGION}" \
--instance-ids "${INSTANCE_ID}" \
--query 'Reservations[0].Instances[0].NetworkInterfaces[0].Ipv6Addresses[0].Ipv6Address' \
--output text)"
printf '%s %s %s\n' "${PUBLIC_DNS}" "${PUBLIC_IPV4}" "${PUBLIC_IPV6}"
ping -6 -c 3 "${PUBLIC_IPV6}"
ssh ec2-user@"${PUBLIC_DNS}" 'ip addr show dev eth0'
```
[ one-shot script ]
-------------------
```sh
cat > ~/bin/create-dualstack-vpc <<'EOF'
#!/bin/sh
set -eu
REGION="${1:-${AWS_REGION:-${AWS_DEFAULT_REGION:-us-east-1}}}"
TAG="${TAG:-dualstack}"
VPC_CIDR="${VPC_CIDR:-10.10.0.0/24}"
SUBNET_CIDR_V4="${SUBNET_CIDR_V4:-10.10.0.0/26}"
AZ="$(aws ec2 describe-availability-zones \
--region "${REGION}" \
--filters Name=state,Values=available \
--query 'AvailabilityZones[0].ZoneName' \
--output text)"
VPCID="$(aws ec2 create-vpc \
--region "${REGION}" \
--cidr-block "${VPC_CIDR}" \
--amazon-provided-ipv6-cidr-block \
--query 'Vpc.VpcId' \
--output text)"
aws ec2 create-tags \
--region "${REGION}" \
--resources "${VPCID}" \
--tags Key=Name,Value="${TAG}"
aws ec2 modify-vpc-attribute \
--region "${REGION}" \
--vpc-id "${VPCID}" \
--enable-dns-support '{"Value":true}'
aws ec2 modify-vpc-attribute \
--region "${REGION}" \
--vpc-id "${VPCID}" \
--enable-dns-hostnames '{"Value":true}'
IGW="$(aws ec2 create-internet-gateway \
--region "${REGION}" \
--query 'InternetGateway.InternetGatewayId' \
--output text)"
aws ec2 create-tags \
--region "${REGION}" \
--resources "${IGW}" \
--tags Key=Name,Value="${TAG}"
aws ec2 attach-internet-gateway \
--region "${REGION}" \
--vpc-id "${VPCID}" \
--internet-gateway-id "${IGW}"
V6CIDR="$(aws ec2 describe-vpcs \
--region "${REGION}" \
--vpc-ids "${VPCID}" \
--query 'Vpcs[0].Ipv6CidrBlockAssociationSet[0].Ipv6CidrBlock' \
--output text)"
SUBNET_CIDR_V6="${V6CIDR%/56}/64"
SUBNET="$(aws ec2 create-subnet \
--region "${REGION}" \
--vpc-id "${VPCID}" \
--cidr-block "${SUBNET_CIDR_V4}" \
--ipv6-cidr-block "${SUBNET_CIDR_V6}" \
--availability-zone "${AZ}" \
--query 'Subnet.SubnetId' \
--output text)"
aws ec2 create-tags \
--region "${REGION}" \
--resources "${SUBNET}" \
--tags Key=Name,Value="${TAG}"
aws ec2 modify-subnet-attribute \
--region "${REGION}" \
--subnet-id "${SUBNET}" \
--assign-ipv6-address-on-creation
aws ec2 modify-subnet-attribute \
--region "${REGION}" \
--subnet-id "${SUBNET}" \
--map-public-ip-on-launch
RTB="$(aws ec2 create-route-table \
--region "${REGION}" \
--vpc-id "${VPCID}" \
--query 'RouteTable.RouteTableId' \
--output text)"
aws ec2 create-tags \
--region "${REGION}" \
--resources "${RTB}" \
--tags Key=Name,Value="${TAG}"
aws ec2 associate-route-table \
--region "${REGION}" \
--route-table-id "${RTB}" \
--subnet-id "${SUBNET}" \
>/dev/null
aws ec2 create-route \
--region "${REGION}" \
--route-table-id "${RTB}" \
--destination-cidr-block 0.0.0.0/0 \
--gateway-id "${IGW}" \
>/dev/null
aws ec2 create-route \
--region "${REGION}" \
--route-table-id "${RTB}" \
--destination-ipv6-cidr-block ::/0 \
--gateway-id "${IGW}" \
>/dev/null
SG="$(aws ec2 create-security-group \
--region "${REGION}" \
--group-name "${TAG}" \
--description "Default security group for ${TAG} instances" \
--vpc-id "${VPCID}" \
--query 'GroupId' \
--output text)"
aws ec2 create-tags \
--region "${REGION}" \
--resources "${SG}" \
--tags Key=Name,Value="${TAG}"
aws ec2 authorize-security-group-ingress \
--region "${REGION}" \
--group-id "${SG}" \
--ip-permissions \
'[{"IpProtocol":"-1","IpRanges":[{"CidrIp":"0.0.0.0/0"}],"Ipv6Ranges":[{"CidrIpv6":"::/0"}]}]'
printf 'region=%s vpc=%s subnet=%s sg=%s\n' \
"${REGION}" "${VPCID}" "${SUBNET}" "${SG}"
EOF
chmod 755 ~/bin/create-dualstack-vpc
```
[ launch helper ]
-----------------
```sh
cat >> ~/.bashrc <<'EOF'
start_dualstack_instance() {
region="${1:?region required}"
shift
subnet="$(aws ec2 describe-subnets \
--region "${region}" \
--filters Name=tag:Name,Values=dualstack \
--query 'Subnets[0].SubnetId' \
--output text)"
sg="$(aws ec2 describe-security-groups \
--region "${region}" \
--filters Name=tag:Name,Values=dualstack \
--query 'SecurityGroups[0].GroupId' \
--output text)"
aws ec2 run-instances \
--region "${region}" \
--subnet-id "${subnet}" \
--security-group-ids "${sg}" \
"$@"
}
alias start-al2023-use1='start_dualstack_instance us-east-1 \
--image-id resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 \
--instance-type t3.micro'
EOF
```
[ multi-region ]
----------------
```sh
aws configure set region sa-east-1
~/bin/create-dualstack-vpc sa-east-1
aws configure set region us-east-1
~/bin/create-dualstack-vpc us-east-1
start_dualstack_instance sa-east-1 \
--image-id resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 \
--instance-type t3.micro \
--query 'Instances[0].InstanceId' \
--output text
start_dualstack_instance us-east-1 \
--image-id resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 \
--instance-type t3.micro \
--query 'Instances[0].InstanceId' \
--output text
```