NAT Instance (cheap NAT for dev/test)
AWS architecture template · A t3.nano EC2 NAT instance costs ~$3.80/mo vs NAT Gateway ~$32+/mo. Valid for dev/test VPCs with low egress. Not HA — use NAT Gateway for production.
NAT Instance (cheap NAT for dev/test) is a free AWS architecture template built with EC2 and CloudWatch. Open it in TheArchitect to edit the diagram, estimate monthly cost, and export the CloudFormation or Terraform that deploys it.
AWS services in this template
- EC2×2
- CloudWatch
Deployment notes
Needs input
- Set source/destination check to DISABLED on the NAT instance after launch.
- Update private subnet route table: 0.0.0.0/0 → nat-instance-id (not an IGW or NAT GW).
- Not HA by default — single point of failure. For production, use NAT Gateway per AZ instead.
- Cost: t3.nano ~$3.80/mo + data transfer. NAT Gateway: $0.045/hr (~$32/mo) + $0.045/GB processed.
Generated CloudFormation — 33 resources
| Logical ID | Resource type |
|---|---|
| DevTestVPC1000016vpc | AWS::EC2::VPC |
| DevTestVPC1000016vpcedgewebsgSecurityGroup | AWS::EC2::SecurityGroup |
| DevTestVPC1000016vpcappruntimesgSecurityGroup | AWS::EC2::SecurityGroup |
| DevTestVPC1000016vpcappruntimesgSecurityGroupIngressRule | AWS::EC2::SecurityGroupIngress |
| DevTestVPC1000016vpcworkersgSecurityGroup | AWS::EC2::SecurityGroup |
| DevTestVPC1000016vpcdatastoresgSecurityGroup | AWS::EC2::SecurityGroup |
| DevTestVPC1000016vpcdatastoresgSecurityGroupIngressRule | AWS::EC2::SecurityGroupIngress |
| DevTestVPC1000016vpccontrolplanesgSecurityGroup | AWS::EC2::SecurityGroup |
| DevTestVPC1000016vpcPublicSubnet1 | AWS::EC2::Subnet |
| DevTestVPC1000016vpcPublicSubnet2 | AWS::EC2::Subnet |
| DevTestVPC1000016vpcPrivateSubnet1 | AWS::EC2::Subnet |
| DevTestVPC1000016vpcPrivateSubnet2 | AWS::EC2::Subnet |
| DevTestVPC1000016vpcPrivateSubnet3 | AWS::EC2::Subnet |
| DevTestVPC1000016vpcPrivateSubnet4 | AWS::EC2::Subnet |
| DevTestVPC1000016vpcInternetGateway | AWS::EC2::InternetGateway |
| DevTestVPC1000016vpcGatewayAttachment | AWS::EC2::VPCGatewayAttachment |
| DevTestVPC1000016vpcPublicRouteTable | AWS::EC2::RouteTable |
| DevTestVPC1000016vpcPublicRoute | AWS::EC2::Route |
| DevTestVPC1000016vpcPublicSubnet1RTA | AWS::EC2::SubnetRouteTableAssociation |
| DevTestVPC1000016vpcPublicSubnet2RTA | AWS::EC2::SubnetRouteTableAssociation |
| DevTestVPC1000016vpcNatEIP | AWS::EC2::EIP |
| DevTestVPC1000016vpcNatGateway | AWS::EC2::NatGateway |
| DevTestVPC1000016vpcPrivateRouteTable | AWS::EC2::RouteTable |
| DevTestVPC1000016vpcPrivateRoute | AWS::EC2::Route |
| DevTestVPC1000016vpcPrivateSubnet1RTA | AWS::EC2::SubnetRouteTableAssociation |
| DevTestVPC1000016vpcPrivateSubnet2RTA | AWS::EC2::SubnetRouteTableAssociation |
| DevTestVPC1000016vpcPrivateSubnet3RTA | AWS::EC2::SubnetRouteTableAssociation |
| DevTestVPC1000016vpcPrivateSubnet4RTA | AWS::EC2::SubnetRouteTableAssociation |
| PublicSubnet1001024subnet | AWS::EC2::Subnet |
| PrivateSubnet10011024subnet | AWS::EC2::Subnet |
| NATInstancet3nanoec2 | AWS::EC2::Instance |
| AppServerprivateec2 | AWS::EC2::Instance |
| NATCPUAlarmcloudwatch | AWS::CloudWatch::Alarm |
View the full CloudFormation template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Generated by TheArchitect — https://www.thecloudarchitect.dev",
"Resources": {
"DevTestVPC1000016vpc": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": "10.0.0.0/16",
"EnableDnsHostnames": true,
"EnableDnsSupport": true,
"Tags": [
{
"Key": "Name",
"Value": "cost-nat-vpc"
}
]
}
},
"DevTestVPC1000016vpcedgewebsgSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "edge-web-sg",
"GroupDescription": "Allow HTTPS from the internet to public load balancers",
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "edge-web-sg"
}
],
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": 443,
"ToPort": 443,
"CidrIp": "0.0.0.0/0"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "-1",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"DevTestVPC1000016vpcappruntimesgSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "app-runtime-sg",
"GroupDescription": "Allow application traffic from the edge tier",
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "app-runtime-sg"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "-1",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"DevTestVPC1000016vpcappruntimesgSecurityGroupIngressRule": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "DevTestVPC1000016vpcappruntimesgSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": 80,
"ToPort": 80,
"SourceSecurityGroupId": {
"Ref": "DevTestVPC1000016vpcedgewebsgSecurityGroup"
}
}
},
"DevTestVPC1000016vpcworkersgSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "worker-sg",
"GroupDescription": "Private worker runtime egress only",
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "worker-sg"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "-1",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"DevTestVPC1000016vpcdatastoresgSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "data-store-sg",
"GroupDescription": "Allow PostgreSQL from application runtimes",
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "data-store-sg"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "-1",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"DevTestVPC1000016vpcdatastoresgSecurityGroupIngressRule": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"GroupId": {
"Ref": "DevTestVPC1000016vpcdatastoresgSecurityGroup"
},
"IpProtocol": "tcp",
"FromPort": 5432,
"ToPort": 5432,
"SourceSecurityGroupId": {
"Ref": "DevTestVPC1000016vpcappruntimesgSecurityGroup"
}
}
},
"DevTestVPC1000016vpccontrolplanesgSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "control-plane-sg",
"GroupDescription": "Private EKS control plane attachment group",
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "control-plane-sg"
}
],
"SecurityGroupEgress": [
{
"IpProtocol": "-1",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"DevTestVPC1000016vpcPublicSubnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"CidrBlock": "10.10.1.0/24",
"AvailabilityZone": "us-east-1a",
"MapPublicIpOnLaunch": true,
"Tags": [
{
"Key": "Name",
"Value": "public-edge-a"
}
]
}
},
"DevTestVPC1000016vpcPublicSubnet2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"CidrBlock": "10.10.2.0/24",
"AvailabilityZone": "us-east-1b",
"MapPublicIpOnLaunch": true,
"Tags": [
{
"Key": "Name",
"Value": "public-edge-b"
}
]
}
},
"DevTestVPC1000016vpcPrivateSubnet1": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"CidrBlock": "10.10.11.0/24",
"AvailabilityZone": "us-east-1a",
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "Name",
"Value": "private-app-a"
}
]
}
},
"DevTestVPC1000016vpcPrivateSubnet2": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"CidrBlock": "10.10.12.0/24",
"AvailabilityZone": "us-east-1b",
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "Name",
"Value": "private-app-b"
}
]
}
},
"DevTestVPC1000016vpcPrivateSubnet3": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"CidrBlock": "10.10.21.0/24",
"AvailabilityZone": "us-east-1a",
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "Name",
"Value": "private-data-a"
}
]
}
},
"DevTestVPC1000016vpcPrivateSubnet4": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"CidrBlock": "10.10.22.0/24",
"AvailabilityZone": "us-east-1b",
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "Name",
"Value": "private-data-b"
}
]
}
},
"DevTestVPC1000016vpcInternetGateway": {
"Type": "AWS::EC2::InternetGateway",
"Properties": {
"Tags": [
{
"Key": "Name",
"Value": "cost-nat-vpc-igw"
}
]
}
},
"DevTestVPC1000016vpcGatewayAttachment": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"InternetGatewayId": {
"Ref": "DevTestVPC1000016vpcInternetGateway"
}
}
},
"DevTestVPC1000016vpcPublicRouteTable": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "cost-nat-vpc-public-rt"
}
]
}
},
"DevTestVPC1000016vpcPublicRoute": {
"Type": "AWS::EC2::Route",
"DependsOn": [
"DevTestVPC1000016vpcGatewayAttachment"
],
"Properties": {
"RouteTableId": {
"Ref": "DevTestVPC1000016vpcPublicRouteTable"
},
"DestinationCidrBlock": "0.0.0.0/0",
"GatewayId": {
"Ref": "DevTestVPC1000016vpcInternetGateway"
}
}
},
"DevTestVPC1000016vpcPublicSubnet1RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "DevTestVPC1000016vpcPublicSubnet1"
},
"RouteTableId": {
"Ref": "DevTestVPC1000016vpcPublicRouteTable"
}
}
},
"DevTestVPC1000016vpcPublicSubnet2RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "DevTestVPC1000016vpcPublicSubnet2"
},
"RouteTableId": {
"Ref": "DevTestVPC1000016vpcPublicRouteTable"
}
}
},
"DevTestVPC1000016vpcNatEIP": {
"Type": "AWS::EC2::EIP",
"DependsOn": [
"DevTestVPC1000016vpcGatewayAttachment"
],
"Properties": {
"Domain": "vpc"
}
},
"DevTestVPC1000016vpcNatGateway": {
"Type": "AWS::EC2::NatGateway",
"Properties": {
"AllocationId": {
"Fn::GetAtt": [
"DevTestVPC1000016vpcNatEIP",
"AllocationId"
]
},
"SubnetId": {
"Ref": "DevTestVPC1000016vpcPublicSubnet1"
},
"Tags": [
{
"Key": "Name",
"Value": "cost-nat-vpc-nat"
}
]
}
},
"DevTestVPC1000016vpcPrivateRouteTable": {
"Type": "AWS::EC2::RouteTable",
"Properties": {
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
},
"Tags": [
{
"Key": "Name",
"Value": "cost-nat-vpc-private-rt"
}
]
}
},
"DevTestVPC1000016vpcPrivateRoute": {
"Type": "AWS::EC2::Route",
"Properties": {
"RouteTableId": {
"Ref": "DevTestVPC1000016vpcPrivateRouteTable"
},
"DestinationCidrBlock": "0.0.0.0/0",
"NatGatewayId": {
"Ref": "DevTestVPC1000016vpcNatGateway"
}
}
},
"DevTestVPC1000016vpcPrivateSubnet1RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "DevTestVPC1000016vpcPrivateSubnet1"
},
"RouteTableId": {
"Ref": "DevTestVPC1000016vpcPrivateRouteTable"
}
}
},
"DevTestVPC1000016vpcPrivateSubnet2RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "DevTestVPC1000016vpcPrivateSubnet2"
},
"RouteTableId": {
"Ref": "DevTestVPC1000016vpcPrivateRouteTable"
}
}
},
"DevTestVPC1000016vpcPrivateSubnet3RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "DevTestVPC1000016vpcPrivateSubnet3"
},
"RouteTableId": {
"Ref": "DevTestVPC1000016vpcPrivateRouteTable"
}
}
},
"DevTestVPC1000016vpcPrivateSubnet4RTA": {
"Type": "AWS::EC2::SubnetRouteTableAssociation",
"Properties": {
"SubnetId": {
"Ref": "DevTestVPC1000016vpcPrivateSubnet4"
},
"RouteTableId": {
"Ref": "DevTestVPC1000016vpcPrivateRouteTable"
}
}
},
"PublicSubnet1001024subnet": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.1.0/24",
"AvailabilityZone": "us-east-1a",
"MapPublicIpOnLaunch": true,
"Tags": [
{
"Key": "Name",
"Value": "cost-pub-subnet"
}
],
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
}
}
},
"PrivateSubnet10011024subnet": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.11.0/24",
"AvailabilityZone": "us-east-1a",
"MapPublicIpOnLaunch": false,
"Tags": [
{
"Key": "Name",
"Value": "cost-priv-subnet"
}
],
"VpcId": {
"Ref": "DevTestVPC1000016vpc"
}
}
},
"NATInstancet3nanoec2": {
"Type": "AWS::EC2::Instance",
"Properties": {
"ImageId": "ami-nat-instance",
"InstanceType": "t3.nano",
"SourceDestCheck": false,
"SubnetId": {
"Ref": "PublicSubnet1001024subnet"
},
"SecurityGroupIds": [
{
"Fn::GetAtt": [
"DevTestVPC1000016vpc",
"DefaultSecurityGroup"
]
}
]
}
},
"AppServerprivateec2": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": "t3.micro",
"SubnetId": {
"Ref": "PrivateSubnet10011024subnet"
},
"SecurityGroupIds": [
{
"Fn::GetAtt": [
"DevTestVPC1000016vpc",
"DefaultSecurityGroup"
]
}
]
}
},
"NATCPUAlarmcloudwatch": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName": "cost-nat-cpu",
"AlarmDescription": "Alert when NAT instance CPU > 80 % — consider upgrading instance type or moving to NAT Gateway",
"Namespace": "AWS/EC2",
"MetricName": "CPUUtilization",
"Statistic": "Average",
"Period": 300,
"EvaluationPeriods": 3,
"Threshold": 80,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "notBreaching"
}
}
}
}Generated by TheArchitect from the diagram above. Review values such as names, CIDR ranges and instance sizes before deploying to your account.
Related templates
- Cost OptimizationSAA-C03: CloudWatch budget alarm → Lambda optimiser → Auto Scaling (Spot) + EC2 + S3 (lifecycle) + RDS (right-sized)
- Spot Batch Processing (up to 90 % savings)SQS-driven Auto Scaling Group of Spot EC2 workers. Scale-in on empty queue, handle Spot interruptions via SQS visibility timeout re-queue.
- Secrets Rotation & Compliance AuditZero hardcoded credentials: EC2 fetches DB credentials from Secrets Manager with automatic 30-day rotation. CloudTrail captures every API call to an immutable S3 audit bucket.