NatGateway
An AWS NAT Gateway enables instances in private subnets to connect to the internet or other AWS services while preventing the internet from initiating connections to those instances. NAT Gateways are managed by AWS and provide high availability within an Availability Zone.
Minimal Example
Section titled “Minimal Example”Create a basic NAT Gateway in a public subnet:
import { Vpc, Subnet, NatGateway } from "alchemy/aws/ec2";
const vpc = await Vpc("main-vpc", { cidrBlock: "10.0.0.0/16"});
const publicSubnet = await Subnet("public-subnet", { vpc: vpc, cidrBlock: "10.0.1.0/24", availabilityZone: "us-east-1a", mapPublicIpOnLaunch: true});
const natGateway = await NatGateway("main-nat", { subnet: publicSubnet});
NAT Gateway with Custom Elastic IP
Section titled “NAT Gateway with Custom Elastic IP”Use an existing Elastic IP allocation:
import { Vpc, Subnet, NatGateway } from "alchemy/aws/ec2";
const vpc = await Vpc("web-vpc", { cidrBlock: "10.0.0.0/16"});
const publicSubnet = await Subnet("public-subnet", { vpc: vpc, cidrBlock: "10.0.1.0/24", availabilityZone: "us-east-1a", mapPublicIpOnLaunch: true});
const natGateway = await NatGateway("web-nat", { subnet: publicSubnet, allocationId: "eipalloc-1234567890abcdef0", // Existing EIP tags: { Name: "web-nat-gateway", Environment: "production" }});
Private NAT Gateway
Section titled “Private NAT Gateway”Create a private NAT Gateway for VPC-to-VPC communication:
import { Vpc, Subnet, NatGateway } from "alchemy/aws/ec2";
const vpc = await Vpc("private-vpc", { cidrBlock: "10.0.0.0/16"});
const privateSubnet = await Subnet("nat-subnet", { vpc: vpc, cidrBlock: "10.0.1.0/24", availabilityZone: "us-east-1a"});
const privateNatGateway = await NatGateway("private-nat", { subnet: privateSubnet, connectivityType: "private", tags: { Name: "private-nat-gateway", Type: "private", Purpose: "vpc-to-vpc-communication" }});
Multi-AZ NAT Gateway Setup
Section titled “Multi-AZ NAT Gateway Setup”Create NAT Gateways in multiple Availability Zones for high availability:
import { Vpc, Subnet, InternetGateway, InternetGatewayAttachment, NatGateway, RouteTable, Route, RouteTableAssociation} from "alchemy/aws/ec2";
const vpc = await Vpc("ha-vpc", { cidrBlock: "10.0.0.0/16", enableDnsHostnames: true, enableDnsSupport: true, tags: { Name: "high-availability-vpc" }});
// Internet Gatewayconst igw = await InternetGateway("ha-igw", { tags: { Name: "ha-internet-gateway" }});
const igwAttachment = await InternetGatewayAttachment("ha-igw-attachment", { internetGateway: igw, vpc: vpc});
// Public subnets for NAT Gatewaysconst publicSubnet1a = await Subnet("public-subnet-1a", { vpc: vpc, cidrBlock: "10.0.1.0/24", availabilityZone: "us-east-1a", mapPublicIpOnLaunch: true, tags: { Name: "public-subnet-1a", Type: "public" }});
const publicSubnet1b = await Subnet("public-subnet-1b", { vpc: vpc, cidrBlock: "10.0.2.0/24", availabilityZone: "us-east-1b", mapPublicIpOnLaunch: true, tags: { Name: "public-subnet-1b", Type: "public" }});
const publicSubnet1c = await Subnet("public-subnet-1c", { vpc: vpc, cidrBlock: "10.0.3.0/24", availabilityZone: "us-east-1c", mapPublicIpOnLaunch: true, tags: { Name: "public-subnet-1c", Type: "public" }});
// Private subnetsconst privateSubnet1a = await Subnet("private-subnet-1a", { vpc: vpc, cidrBlock: "10.0.11.0/24", availabilityZone: "us-east-1a", tags: { Name: "private-subnet-1a", Type: "private" }});
const privateSubnet1b = await Subnet("private-subnet-1b", { vpc: vpc, cidrBlock: "10.0.12.0/24", availabilityZone: "us-east-1b", tags: { Name: "private-subnet-1b", Type: "private" }});
const privateSubnet1c = await Subnet("private-subnet-1c", { vpc: vpc, cidrBlock: "10.0.13.0/24", availabilityZone: "us-east-1c", tags: { Name: "private-subnet-1c", Type: "private" }});
// NAT Gateways in each AZconst natGateway1a = await NatGateway("nat-gateway-1a", { subnet: publicSubnet1a, tags: { Name: "nat-gateway-1a", AvailabilityZone: "us-east-1a" }});
const natGateway1b = await NatGateway("nat-gateway-1b", { subnet: publicSubnet1b, tags: { Name: "nat-gateway-1b", AvailabilityZone: "us-east-1b" }});
const natGateway1c = await NatGateway("nat-gateway-1c", { subnet: publicSubnet1c, tags: { Name: "nat-gateway-1c", AvailabilityZone: "us-east-1c" }});
// Public route table (shared)const publicRouteTable = await RouteTable("public-rt", { vpc: vpc, tags: { Name: "public-route-table" }});
const publicInternetRoute = await Route("public-internet-route", { routeTable: publicRouteTable, destinationCidrBlock: "0.0.0.0/0", target: { internetGateway: igw }});
// Private route tables (one per AZ)const privateRouteTable1a = await RouteTable("private-rt-1a", { vpc: vpc, tags: { Name: "private-route-table-1a", AvailabilityZone: "us-east-1a" }});
const privateRouteTable1b = await RouteTable("private-rt-1b", { vpc: vpc, tags: { Name: "private-route-table-1b", AvailabilityZone: "us-east-1b" }});
const privateRouteTable1c = await RouteTable("private-rt-1c", { vpc: vpc, tags: { Name: "private-route-table-1c", AvailabilityZone: "us-east-1c" }});
// NAT routesconst natRoute1a = await Route("nat-route-1a", { routeTable: privateRouteTable1a, destinationCidrBlock: "0.0.0.0/0", target: { natGateway: natGateway1a }});
const natRoute1b = await Route("nat-route-1b", { routeTable: privateRouteTable1b, destinationCidrBlock: "0.0.0.0/0", target: { natGateway: natGateway1b }});
const natRoute1c = await Route("nat-route-1c", { routeTable: privateRouteTable1c, destinationCidrBlock: "0.0.0.0/0", target: { natGateway: natGateway1c }});
// Route table associationsconst publicAssociation1a = await RouteTableAssociation("public-association-1a", { routeTable: publicRouteTable, subnet: publicSubnet1a});
const publicAssociation1b = await RouteTableAssociation("public-association-1b", { routeTable: publicRouteTable, subnet: publicSubnet1b});
const publicAssociation1c = await RouteTableAssociation("public-association-1c", { routeTable: publicRouteTable, subnet: publicSubnet1c});
const privateAssociation1a = await RouteTableAssociation("private-association-1a", { routeTable: privateRouteTable1a, subnet: privateSubnet1a});
const privateAssociation1b = await RouteTableAssociation("private-association-1b", { routeTable: privateRouteTable1b, subnet: privateSubnet1b});
const privateAssociation1c = await RouteTableAssociation("private-association-1c", { routeTable: privateRouteTable1c, subnet: privateSubnet1c});
Cost-Optimized Single NAT Gateway
Section titled “Cost-Optimized Single NAT Gateway”Single NAT Gateway for development or cost-conscious environments:
import { Vpc, Subnet, NatGateway, RouteTable, Route, RouteTableAssociation} from "alchemy/aws/ec2";
const vpc = await Vpc("dev-vpc", { cidrBlock: "10.0.0.0/16"});
// Single public subnet for NAT Gatewayconst publicSubnet = await Subnet("dev-public-subnet", { vpc: vpc, cidrBlock: "10.0.1.0/24", availabilityZone: "us-east-1a", mapPublicIpOnLaunch: true, tags: { Name: "dev-public-subnet" }});
// Multiple private subnetsconst privateSubnet1a = await Subnet("dev-private-subnet-1a", { vpc: vpc, cidrBlock: "10.0.11.0/24", availabilityZone: "us-east-1a", tags: { Name: "dev-private-subnet-1a" }});
const privateSubnet1b = await Subnet("dev-private-subnet-1b", { vpc: vpc, cidrBlock: "10.0.12.0/24", availabilityZone: "us-east-1b", tags: { Name: "dev-private-subnet-1b" }});
// Single NAT Gateway for cost optimizationconst sharedNatGateway = await NatGateway("shared-nat", { subnet: publicSubnet, tags: { Name: "shared-development-nat", Environment: "development", CostOptimization: "shared-across-azs" }});
// Shared private route tableconst sharedPrivateRouteTable = await RouteTable("shared-private-rt", { vpc: vpc, tags: { Name: "shared-private-route-table", Environment: "development" }});
const sharedNatRoute = await Route("shared-nat-route", { routeTable: sharedPrivateRouteTable, destinationCidrBlock: "0.0.0.0/0", target: { natGateway: sharedNatGateway }});
// Associate both private subnets with shared route tableconst privateAssociation1a = await RouteTableAssociation("dev-private-association-1a", { routeTable: sharedPrivateRouteTable, subnet: privateSubnet1a});
const privateAssociation1b = await RouteTableAssociation("dev-private-association-1b", { routeTable: sharedPrivateRouteTable, subnet: privateSubnet1b});
NAT Gateway with Custom Timeout
Section titled “NAT Gateway with Custom Timeout”Configure timeout settings for environments with slower provisioning:
import { Vpc, Subnet, NatGateway } from "alchemy/aws/ec2";
const vpc = await Vpc("slow-vpc", { cidrBlock: "10.0.0.0/16"});
const publicSubnet = await Subnet("slow-public-subnet", { vpc: vpc, cidrBlock: "10.0.1.0/24", availabilityZone: "us-east-1a", mapPublicIpOnLaunch: true});
const slowNatGateway = await NatGateway("slow-nat", { subnet: publicSubnet, timeout: { maxAttempts: 120, // NAT Gateways can take up to 10 minutes delayMs: 5000 // 5 second delay between checks }, tags: { Name: "slow-environment-nat" }});
Reference by Subnet ID
Section titled “Reference by Subnet ID”Create NAT Gateway using subnet ID:
import { NatGateway } from "alchemy/aws/ec2";
const existingSubnetNat = await NatGateway("existing-subnet-nat", { subnet: "subnet-1234567890abcdef0", tags: { Name: "existing-subnet-nat-gateway" }});
Microservices NAT Gateway
Section titled “Microservices NAT Gateway”NAT Gateway setup for microservices architecture:
import { Vpc, Subnet, NatGateway, RouteTable, Route, RouteTableAssociation} from "alchemy/aws/ec2";
const vpc = await Vpc("microservices-vpc", { cidrBlock: "10.0.0.0/16"});
// Public subnet for NAT Gatewayconst natSubnet = await Subnet("nat-subnet", { vpc: vpc, cidrBlock: "10.0.1.0/24", availabilityZone: "us-east-1a", mapPublicIpOnLaunch: true, tags: { Name: "nat-subnet", Purpose: "nat-gateway" }});
// Private subnets for microservicesconst servicesSubnet1a = await Subnet("services-subnet-1a", { vpc: vpc, cidrBlock: "10.0.11.0/24", availabilityZone: "us-east-1a", tags: { Name: "microservices-subnet-1a", Tier: "microservices" }});
const servicesSubnet1b = await Subnet("services-subnet-1b", { vpc: vpc, cidrBlock: "10.0.12.0/24", availabilityZone: "us-east-1b", tags: { Name: "microservices-subnet-1b", Tier: "microservices" }});
// Shared services subnetconst sharedSubnet = await Subnet("shared-subnet", { vpc: vpc, cidrBlock: "10.0.21.0/24", availabilityZone: "us-east-1a", tags: { Name: "shared-services-subnet", Tier: "shared-services" }});
// NAT Gateway for outbound accessconst microservicesNat = await NatGateway("microservices-nat", { subnet: natSubnet, tags: { Name: "microservices-nat-gateway", Architecture: "microservices", Purpose: "outbound-internet-access" }});
// Route tables and routesconst servicesRouteTable = await RouteTable("services-rt", { vpc: vpc, tags: { Name: "microservices-route-table" }});
const sharedRouteTable = await RouteTable("shared-rt", { vpc: vpc, tags: { Name: "shared-services-route-table" }});
const servicesNatRoute = await Route("services-nat-route", { routeTable: servicesRouteTable, destinationCidrBlock: "0.0.0.0/0", target: { natGateway: microservicesNat }});
const sharedNatRoute = await Route("shared-nat-route", { routeTable: sharedRouteTable, destinationCidrBlock: "0.0.0.0/0", target: { natGateway: microservicesNat }});
// Associationsconst servicesAssociation1a = await RouteTableAssociation("services-association-1a", { routeTable: servicesRouteTable, subnet: servicesSubnet1a});
const servicesAssociation1b = await RouteTableAssociation("services-association-1b", { routeTable: servicesRouteTable, subnet: servicesSubnet1b});
const sharedAssociation = await RouteTableAssociation("shared-association", { routeTable: sharedRouteTable, subnet: sharedSubnet});
Database Access Pattern
Section titled “Database Access Pattern”NAT Gateway for database maintenance and updates:
import { Vpc, Subnet, NatGateway, RouteTable, Route, RouteTableAssociation} from "alchemy/aws/ec2";
const vpc = await Vpc("database-vpc", { cidrBlock: "10.0.0.0/16"});
// Public subnet for NAT Gatewayconst natSubnet = await Subnet("db-nat-subnet", { vpc: vpc, cidrBlock: "10.0.1.0/24", availabilityZone: "us-east-1a", mapPublicIpOnLaunch: true});
// Database subnets (normally isolated)const dbSubnet1a = await Subnet("db-subnet-1a", { vpc: vpc, cidrBlock: "10.0.11.0/24", availabilityZone: "us-east-1a", tags: { Name: "database-subnet-1a", Tier: "database" }});
const dbSubnet1b = await Subnet("db-subnet-1b", { vpc: vpc, cidrBlock: "10.0.12.0/24", availabilityZone: "us-east-1b", tags: { Name: "database-subnet-1b", Tier: "database" }});
// NAT Gateway for database maintenance accessconst dbMaintenanceNat = await NatGateway("db-maintenance-nat", { subnet: natSubnet, tags: { Name: "database-maintenance-nat", Purpose: "database-updates-patches", Usage: "maintenance-only" }});
// Maintenance route table (used temporarily)const maintenanceRouteTable = await RouteTable("db-maintenance-rt", { vpc: vpc, tags: { Name: "database-maintenance-route-table", Purpose: "temporary-internet-access" }});
const maintenanceNatRoute = await Route("maintenance-nat-route", { routeTable: maintenanceRouteTable, destinationCidrBlock: "0.0.0.0/0", target: { natGateway: dbMaintenanceNat }});
// Normal isolated route table (no internet access)const isolatedRouteTable = await RouteTable("db-isolated-rt", { vpc: vpc, tags: { Name: "database-isolated-route-table", Purpose: "no-internet-access" }});
// Default associations (isolated)const isolatedAssociation1a = await RouteTableAssociation("db-isolated-association-1a", { routeTable: isolatedRouteTable, subnet: dbSubnet1a});
const isolatedAssociation1b = await RouteTableAssociation("db-isolated-association-1b", { routeTable: isolatedRouteTable, subnet: dbSubnet1b});
Reference
Section titled “Reference”Access NAT Gateway properties after creation:
const natGateway = await NatGateway("my-nat", { subnet: publicSubnet, tags: { Name: "my-nat-gateway" }});
console.log(`NAT Gateway ID: ${natGateway.natGatewayId}`);console.log(`Subnet ID: ${natGateway.subnetId}`);console.log(`VPC ID: ${natGateway.vpcId}`);console.log(`State: ${natGateway.state}`);console.log(`Allocation ID: ${natGateway.allocationId}`);console.log(`Public IP: ${natGateway.publicIp}`);console.log(`Private IP: ${natGateway.privateIp}`);console.log(`Created Elastic IP: ${natGateway.createdElasticIp}`);
If Alchemy creates an Elastic IP for the NAT Gateway, it will also clean up the Elastic IP when the NAT Gateway is destroyed. If you provide your own allocationId
, you’re responsible for managing that Elastic IP.