Skip to content
GitHubXDiscordRSS

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.

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
});

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"
}
});

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"
}
});

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 Gateway
const 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 Gateways
const 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 subnets
const 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 AZ
const 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 routes
const 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 associations
const 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
});

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 Gateway
const 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 subnets
const 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 optimization
const sharedNatGateway = await NatGateway("shared-nat", {
subnet: publicSubnet,
tags: {
Name: "shared-development-nat",
Environment: "development",
CostOptimization: "shared-across-azs"
}
});
// Shared private route table
const 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 table
const privateAssociation1a = await RouteTableAssociation("dev-private-association-1a", {
routeTable: sharedPrivateRouteTable,
subnet: privateSubnet1a
});
const privateAssociation1b = await RouteTableAssociation("dev-private-association-1b", {
routeTable: sharedPrivateRouteTable,
subnet: privateSubnet1b
});

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"
}
});

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"
}
});

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 Gateway
const 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 microservices
const 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 subnet
const 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 access
const microservicesNat = await NatGateway("microservices-nat", {
subnet: natSubnet,
tags: {
Name: "microservices-nat-gateway",
Architecture: "microservices",
Purpose: "outbound-internet-access"
}
});
// Route tables and routes
const 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 }
});
// Associations
const 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
});

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 Gateway
const 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 access
const 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
});

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.