Low cost AWS VPC for an Amazon ECS cluster

Nathan Peck profile picture
Nathan Peck
Senior Developer Advocate at AWS


Amazon Virtual Private Cloud (Amazon VPC) gives you full control over your virtual networking environment, including resource placement, connectivity, and security.

The ideal way to configure a VPC is to use both public and private subnets. The public subnets are used for hosting internet facing resources like load balancers, while the private subnets are used to host application containers and other private resources.

However, private subnets need a NAT gateway for internet access, and NAT gateways comes with both an hourly fee, as well as an additional charge per GB of data that goes through the NAT gateway.

For this reason you may prefer to use a VPC that has exclusively public subnets. You can always upgrade to add NAT gateways and private subnets later on.


The following diagram shows the architecture of what will be created:

VPCPublic subnetPublic subnetInternet gatewayOutbound internet trafficOutbound internet traffic

  • The VPC that is created spans two availability zones. This gives you increased availability.
  • Each AZ has a single public subnet. Internet traffic originating from these subnets goes directly to the internet gateway.


This low cost architecture is designed for very small deployments, as each resource launched into the public subnet must have a public IPv4 address assigned to it in order to actually use the internet gateway.

As of February 1, 2024 all public IPv4 addresses on your AWS account are billed. Large deployments that would require many public IPv4 addresses should migrate to a more complex but cost efficient architecture that utilizes private subnets and private IP addresses. See the following two options:

Subnet Compatibility

For this example VPC the following table shows subnet support for internet access and networking across each capacity and networking mode.

ConfigurationPublic Subnets
EC2 Bridge mode
EC2 Host mode
EC2 AWS VPC❌ (not supported, EC2 tasks don't have public IP's)
Fargate AWS VPC❗ (requires assign public IP)


AWS VPC on EC2 will not work in this VPC because task ENI's on EC2 can not be assigned public IP addresses, and therefore the task can not utilize the internet gateway.


AWS Fargate tasks must be launched with "assign public IP" turned on. This allows them to use the internet gateway directly. But if you don't turn on public IP assignment then internet access will not work.

VPC Configuration

Deploy the following CloudFormation template to create the VPC:

File: vpc.ymlLanguage: yml
AWSTemplateFormatVersion: '2010-09-09'
Description: This stack deploys a large AWS VPC with internet access
  # Hard values for the subnet masks. These masks define
  # the range of internal IP addresses that can be assigned.
  # The VPC can have all IP's from to
  # There are two subnets which cover the ranges:
  # - (16384 IP addresses)
  # - (16384 IP addresses)
      CIDR: ''
      CIDR: ''
      CIDR: ''
  # VPC in which containers will be networked.
  # It has two public subnets.
  # We distribute the subnets across the first two available subnets
  # for the region, for high availability.
    Type: AWS::EC2::VPC
      EnableDnsSupport: true
      EnableDnsHostnames: true
      CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']

  # Two public subnets, where containers can have public IP addresses
    Type: AWS::EC2::Subnet
         - 0
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR']
      MapPublicIpOnLaunch: true
    Type: AWS::EC2::Subnet
         - 1
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR']
      MapPublicIpOnLaunch: true

  # Setup networking resources for the public subnets. Containers
  # in the public subnets have public IP addresses and the routing table
  # sends network traffic via the internet gateway.
    Type: AWS::EC2::InternetGateway
    Type: AWS::EC2::VPCGatewayAttachment
      VpcId: !Ref 'VPC'
      InternetGatewayId: !Ref 'InternetGateway'
    Type: AWS::EC2::RouteTable
      VpcId: !Ref 'VPC'
    Type: AWS::EC2::Route
    DependsOn: GatewayAttachement
      RouteTableId: !Ref 'PublicRouteTable'
      DestinationCidrBlock: ''
      GatewayId: !Ref 'InternetGateway'
    Type: AWS::EC2::SubnetRouteTableAssociation
      SubnetId: !Ref PublicSubnetOne
      RouteTableId: !Ref PublicRouteTable
    Type: AWS::EC2::SubnetRouteTableAssociation
      SubnetId: !Ref PublicSubnetTwo
      RouteTableId: !Ref PublicRouteTable

    Description: The ID of the VPC that this stack is deployed in
    Value: !Ref 'VPC'
    Description: Comma seperated list of public facing subnets that have
                 a direct internet connection as long as you assign a public IP
    Value: !Sub '${PublicSubnetOne},${PublicSubnetTwo}'

Some things to note:

This pattern VPC has two public subnets, each with 16,384 addresses. These subnets should be used to hosting public facing load balancers, or other similar resources that are intended to accept direct inbound traffic from the internet.


Deploy the template via the AWS CloudFormation console, or with a CLI command like this:

Language: shell
aws cloudformation deploy \
   --stack-name big-vpc \
   --template-file vpc.yml

The deployed template has Outputs that you can pass into other stacks:

  • VpcId - Many other AWS resources will need to know the ID of the VPC that they are placed in.
  • PublicSubnetIds - A comma separated list of the subnet ID's that have direct internet access.

Next Steps

  • This template only provisions two subnets. For even greater availability consider adding a third public subnet.
  • If you wish to utilize AWS VPC networking mode on EC2 or just want to run your application containers in a private subnet then considering upgrading to the large VPC for Amazon ECS cluster.