ЁЯПл The SchoolтА║ЁЯЪк NATтА║ЁЯТ░ рдзрдбрд╛ 06 тАФ рдлрд╛рдЯрдХрд╛рдЪрд╛ рдЦрд░реНрдЪ рдХрд┐рддреА
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯТ░ рдзрдбрд╛ 06 тАФ рдлрд╛рдЯрдХрд╛рдЪрд╛ рдЦрд░реНрдЪ рдХрд┐рддреА

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 8 рдкреИрдХреА рдзрдбрд╛ 06 ┬╖ рдорд╛рдЧреЗ: lesson-05-elastic-ips ┬╖ рдкреБрдвреЗ: lesson-07-alternatives


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ05, рдЖрдгрд┐ NAT gateway рдЪреЗ bill: рдПрдХ рддрд╛рд╕рд╛рдЪрд╛ рдореАрдЯрд░ рдЖрдгрд┐ рдПрдХ per-GB рдореАрдЯрд░, cross-AZ traffic рдореБрд│реЗ рдХрд╛рдп рд╡рд╛рдврддреЗ, рдЖрдгрд┐ рдЕрдиреЗрдХ teams рд╕рд╛рдареА рд╕рд░реНрд╡рд╛рдд рдореЛрдард╛ рднрд╛рдЧ рдХрд╛рдвреВрди рдЯрд╛рдХрдгрд╛рд░рд╛ рдореЛрдлрдд рдмреЛрдЧрджрд╛ (S3 gateway endpoint). nat/demo.py рдордзреАрд▓ costs() рдЖрдгрд┐ nat/gateway.py рдордзреАрд▓ monthly_cost().

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдлрд╛рдЯрдХ рдХрдВрдкрдиреАрдиреЗ рдлрд╛рдЯрдХрд╛рд╡рд░ рджреЛрди рдореАрдЯрд░ тП▒я╕ПЁЯУж рд▓рд╛рд╡рд▓реЗ рдЖрд╣реЗрдд:

рдирдВрддрд░ рд▓рдХреНрд╖рд╛рдд рдпреЗрддреЗ рдХреА рдмрд╣реБрддреЗрдХ рдкрд┐рд╢рд╡реНрдпрд╛ рдореНрд╣рдгрдЬреЗ рдЧрд╛рд╡рд╛рддрд▓реНрдпрд╛ рдЧреНрд░рдВрдерд╛рд▓рдпрд╛рддреАрд▓ ЁЯУЪ рдкреБрд╕реНрддрдХреЗ рдЖрд╣реЗрдд. рдЖрдгрд┐ рд╢рд╛рд│реЗрддреВрди рдереЗрдЯ рдЧреНрд░рдВрдерд╛рд▓рдпрд╛рдкрд░реНрдпрдВрдд рдПрдХ рдореЛрдлрдд рдмреЛрдЧрджрд╛ рдЖрд╣реЗ. рдЧреНрд░рдВрдерд╛рд▓рдпрд╛рдЪреНрдпрд╛ рдлреЗрд▒реНрдпрд╛ рдмреЛрдЧрджреНрдпрд╛рддреВрди рдкрд╛рдард╡рд╛, рдЖрдгрд┐ рдкрд┐рд╢рд╡реНрдпрд╛рдВрдЪрд╛ рдореАрдЯрд░ рдЬрд╡рд│рдЬрд╡рд│ рдерд╛рдВрдмрддреЛ.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    desks["ЁЯкС private desks"]
    gate["ЁЯЪк NAT gateway<br/>тП▒я╕П $0.045 / hour<br/>ЁЯУж $0.045 / GB"]
    tunnel["ЁЯЪЗ S3 gateway endpoint<br/>free тАФ just a route"]
    s3["ЁЯУЪ Amazon S3"]
    net["ЁЯМР internet APIs"]
    desks -->|"1 1,000 GB"| gate --> net
    desks -->|"2 4,000 GB"| tunnel --> s3

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/nat/lesson-diagrams.html#l06

тЭУ рдХрд╛рдп

рдЗрдерд▓реНрдпрд╛ рд╕рдЧрд│реНрдпрд╛ рдХрд┐рдорддреА us-east-1 рдЪреНрдпрд╛ рдЙрджрд╛рд╣рд░рдг рдХрд┐рдорддреА рдЖрд╣реЗрдд (рддреНрдпрд╛ region рдиреБрд╕рд╛рд░ рдмрджрд▓рддрд╛рдд тАФ рдиреЗрд╣рдореА AWS pricing page рддрдкрд╛рд╕рд╛):

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг per-GB рдореАрдЯрд░ teams рдирд╛ рдЖрд╢реНрдЪрд░реНрдпрдЪрдХрд┐рдд рдХрд░рддреЛ: NAT рдордзреВрди S3 рд╡рд░реВрди container images, backups рдХрд┐рдВрд╡рд╛ data files рдУрдврдгрд╛рд▒реНрдпрд╛ job рдЪрд╛ рдЦрд░реНрдЪ рддреЗ рдХрд╛рдо рдХрд░рдгрд╛рд▒реНрдпрд╛ servers рдкреЗрдХреНрд╖рд╛рд╣реА рдЬрд╛рд╕реНрдд рд╣реЛрдК рд╢рдХрддреЛ. рдЙрдкрд╛рдп рдмрд░реЗрдЪрджрд╛ рдПрдХрдЪ route рдЕрд╕рддреЛ тАФ рдЖрдгрд┐ bill рдпреЗрдИрдкрд░реНрдпрдВрдд рддреЛ рдХреЛрдгреАрдЪ рдЬреЛрдбрдд рдирд╛рд╣реА.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

nat/gateway.py рдордзреАрд▓ monthly_cost(gateways, gb, hours=730, hourly=HOURLY, per_gb=PER_GB) рдореНрд╣рдгрдЬреЗрдЪ рд╣реЗ рджреЛрди рдореАрдЯрд░: gateways ├Ч hours ├Ч hourly + gb ├Ч per_gb. nat/demo.py рдордзреАрд▓ costs() рддреАрди рд░рдЪрдирд╛рдВрдЪреА рдХрд┐рдВрдордд рдЖрдгрд┐ S3 рдореБрд│реЗ рд╣реЛрдгрд╛рд░реА рдмрдЪрдд рдХрд╛рдврддреЗ. Model cross-AZ рдХрд┐рдВрд╡рд╛ internet data transfer рдЬреЛрдбрдд рдирд╛рд╣реА тАФ рддреЗ рдлрдХреНрдд NAT рдЪреНрдпрд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ рджреЛрди рдореАрдЯрд░рдЪреА рдХрд┐рдВрдордд рдХрд╛рдврддреЗ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 nat/demo.py costs
python3 - <<'EOF'
import sys; sys.path.insert(0, "nat"); from gateway import monthly_cost
print("before  3 NAT, 5,000 GB  $", monthly_cost(3, 5000))
print("after   3 NAT, 1,000 GB  $", monthly_cost(3, 1000), "(4,000 GB of S3 moved to a gateway endpoint)")
print("dev VPC 1 NAT, 730 h     $", monthly_cost(1, 20))
print("dev VPC 1 NAT, 60 h      $", monthly_cost(1, 20, hours=60), "(created for 60 hours, then deleted)")
print("hour meter share at 100 GB:", round(monthly_cost(3, 0) / monthly_cost(3, 100) * 100), "%")
EOF

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

costs рд╣реЗ 1 NAT ├Ч 730 h + 100 GB тЖТ $ 37.35 / month, 3 NAT ├Ч 730 h + 100 GB тЖТ $ 103.05 / month, 3 NAT ├Ч 730 h + 5,000 GB тЖТ $ 323.55 / month рдЖрдгрд┐ of those 5,000 GB, 4,000 GB were S3 downloads тАФ a free gateway endpoint saves $180.00 a month рдЫрд╛рдкрддреЗ. рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:

before  3 NAT, 5,000 GB  $ 323.55
after   3 NAT, 1,000 GB  $ 143.55 (4,000 GB of S3 moved to a gateway endpoint)
dev VPC 1 NAT, 730 h     $ 33.75
dev VPC 1 NAT, 60 h      $ 3.6 (created for 60 hours, then deleted)
hour meter share at 100 GB: 96 %

рджреЛрди рд╡реЗрдЧрд│реНрдпрд╛ рдЧреЛрд╖реНрдЯреА. рдХрдореА traffic рдЕрд╕рддрд╛рдирд╛ рддрд╛рд╕рд╛рдЪрд╛ рдореАрдЯрд░ bill рдЪреНрдпрд╛ 96% рдЕрд╕рддреЛ тАФ рдореНрд╣рдгреВрди рд░рд┐рдХрд╛рдорд╛ рдЕрд╕рддрд╛рдирд╛ рдЖрдкрд▓рд╛ NAT delete рдХрд░рдгрд╛рд░реЗ dev VPC рд╕рд░реНрд╡рд╛рдд рдЬрд╛рд╕реНрдд рд╡рд╛рдЪрд╡рддреЗ. рдЬрд╛рд╕реНрдд traffic рдЕрд╕рддрд╛рдирд╛ GB рдореАрдЯрд░ рдЬрд┐рдВрдХрддреЛ тАФ рдореНрд╣рдгреВрди endpoint рд╕рд░реНрд╡рд╛рдд рдЬрд╛рд╕реНрдд рд╡рд╛рдЪрд╡рддреЛ.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

NAT рдЪреЗ bill рдореНрд╣рдгрдЬреЗ рддрд╛рд╕ рдЕрдзрд┐рдХ GB; рдХреЛрдгрддрд╛ рдореАрдЯрд░ рдЪрд╛рд▓реВ рдЖрд╣реЗ рд╣реЗ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд│рддреЗ, рдЖрдгрд┐ рдПрдХрд╛ рдореЛрдлрдд route рдиреЗ рд╣реЗ bill $323.55 рд╡рд░реВрди $143.55 рд╡рд░ рдЖрдгрд▓реЗ.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд

рдЦрд▒реНрдпрд╛ account рд╡рд░ тАФ bill рдордзрд▓рд╛ NAT рдЪрд╛ рднрд╛рдЧ рд╢реЛрдзрд╛, рдордЧ рдкреНрд░рддреНрдпреЗрдХ private route table рдордзреНрдпреЗ рдореЛрдлрдд S3 endpoint рдЬреЛрдбрд╛:

aws ce get-cost-and-usage --time-period Start=2026-08-01,End=2026-09-01 --granularity MONTHLY --metrics UnblendedCost --group-by Type=DIMENSION,Key=USAGE_TYPE --filter '{"Dimensions":{"Key":"SERVICE","Values":["EC2 - Other"]}}'
aws cloudwatch get-metric-statistics --namespace AWS/NATGateway --metric-name BytesOutToDestination --dimensions Name=NatGatewayId,Value=nat-0abc --start-time 2026-09-20T00:00:00Z --end-time 2026-09-27T00:00:00Z --period 86400 --statistics Sum
aws ec2 create-vpc-endpoint --vpc-id vpc-0abc --vpc-endpoint-type Gateway --service-name com.amazonaws.us-east-1.s3 --route-table-ids rtb-private-a rtb-private-b rtb-private-c
resource "aws_vpc_endpoint" "s3" {
  vpc_id            = aws_vpc.main.id
  service_name      = "com.amazonaws.us-east-1.s3"
  vpc_endpoint_type = "Gateway"
  route_table_ids   = [for rt in aws_route_table.private : rt.id]
}

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: S3 рдЖрдгрд┐ DynamoDB gateway endpoints рдкрд╣рд┐рд▓реНрдпрд╛рдЪ рджрд┐рд╡рд╢реА рдЬреЛрдбрд╛ тАФ рддреЗ рдореЛрдлрдд рдЖрд╣реЗрдд тАФ рдЖрдгрд┐ рджрд░ рдорд╣рд┐рдиреНрдпрд╛рд▓рд╛ NatGateway-Bytes рдкрд╛рд╣рд╛. VPC Flow Logs bytes рдХреЛрдгрддреНрдпрд╛ destinations рдХрдбреЗ рдЬрд╛рддрд╛рдд рддреЗ рджрд╛рдЦрд╡рддрд╛рдд.

тПня╕П рдкреБрдвреЗ

S3 рдмреЛрдЧрджрд╛ рд╣рд╛ рдлрд╛рдЯрдХ рдЯрд╛рд│рдгреНрдпрд╛рдЪрд╛ рдПрдХ рдорд╛рд░реНрдЧ рд╣реЛрддрд╛. рдЖрдгрдЦреАрд╣реА рдЖрд╣реЗрдд тАФ рдЖрдгрд┐ рдХрдзреА рдХрдзреА рд╕рд░реНрд╡реЛрддреНрддрдо рдлрд╛рдЯрдХ рдореНрд╣рдгрдЬреЗ рдлрд╛рдЯрдХрдЪ рдирд╛рд╣реА. NAT рдЪреЗ рдкрд░реНрдпрд╛рдп.

git checkout lesson-07-alternatives

ЁЯТ░ Lesson 06 тАФ What the gate costs

ЁЯУН You are here: Lesson 06 of 8 ┬╖ Previous: lesson-05-elastic-ips ┬╖ Next: lesson-07-alternatives


ЁЯУж What's in this branch

Lessons 01тАУ05, plus the NAT gateway bill: an hourly meter and a per-GB meter, what cross-AZ traffic adds, and the free tunnel (an S3 gateway endpoint) that removes the biggest part for many teams. costs() in nat/demo.py and monthly_cost() in nat/gateway.py.

ЁЯзТ Explain like I'm 5

The gate company has two meters тП▒я╕ПЁЯУж on the gate:

Most of the bags turn out to be books from the town library ЁЯУЪ. And there is a free tunnel from the school straight to the library. Send the library trips through the tunnel, and the bag meter almost stops.

ЁЯЧ║я╕П Diagram

flowchart LR
    desks["ЁЯкС private desks"]
    gate["ЁЯЪк NAT gateway<br/>тП▒я╕П $0.045 / hour<br/>ЁЯУж $0.045 / GB"]
    tunnel["ЁЯЪЗ S3 gateway endpoint<br/>free тАФ just a route"]
    s3["ЁЯУЪ Amazon S3"]
    net["ЁЯМР internet APIs"]
    desks -->|"1 1,000 GB"| gate --> net
    desks -->|"2 4,000 GB"| tunnel --> s3

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/nat/lesson-diagrams.html#l06

тЭУ What

All prices here are example prices for us-east-1 (they vary by region тАФ always check the AWS pricing page):

ЁЯдФ Why

Because the per-GB meter surprises teams: a job that pulls container images, backups or data files from S3 through the NAT can cost more than the servers doing the work. The fix is often one route тАФ and nobody adds it until the bill arrives.

ЁЯФз How (in this repo)

monthly_cost(gateways, gb, hours=730, hourly=HOURLY, per_gb=PER_GB) in nat/gateway.py is the two meters: gateways ├Ч hours ├Ч hourly + gb ├Ч per_gb. costs() in nat/demo.py prices three designs and the S3 saving. The model does not add cross-AZ or internet data transfer тАФ it prices only the NAT's own two meters.

ЁЯзк Try it

python3 nat/demo.py costs
python3 - <<'EOF'
import sys; sys.path.insert(0, "nat"); from gateway import monthly_cost
print("before  3 NAT, 5,000 GB  $", monthly_cost(3, 5000))
print("after   3 NAT, 1,000 GB  $", monthly_cost(3, 1000), "(4,000 GB of S3 moved to a gateway endpoint)")
print("dev VPC 1 NAT, 730 h     $", monthly_cost(1, 20))
print("dev VPC 1 NAT, 60 h      $", monthly_cost(1, 20, hours=60), "(created for 60 hours, then deleted)")
print("hour meter share at 100 GB:", round(monthly_cost(3, 0) / monthly_cost(3, 100) * 100), "%")
EOF

тЬЕ Verify тАФ what you should see

costs prints 1 NAT ├Ч 730 h + 100 GB тЖТ $ 37.35 / month, 3 NAT ├Ч 730 h + 100 GB тЖТ $ 103.05 / month, 3 NAT ├Ч 730 h + 5,000 GB тЖТ $ 323.55 / month and of those 5,000 GB, 4,000 GB were S3 downloads тАФ a free gateway endpoint saves $180.00 a month. Your snippet prints:

before  3 NAT, 5,000 GB  $ 323.55
after   3 NAT, 1,000 GB  $ 143.55 (4,000 GB of S3 moved to a gateway endpoint)
dev VPC 1 NAT, 730 h     $ 33.75
dev VPC 1 NAT, 60 h      $ 3.6 (created for 60 hours, then deleted)
hour meter share at 100 GB: 96 %

Two different stories. At low traffic, the hour meter is 96% of the bill тАФ so a dev VPC that deletes its NAT when idle saves the most. At high traffic, the GB meter wins тАФ so the endpoint saves the most.

ЁЯПБ What you just proved

A NAT bill is hours plus GB; you know which meter is running, and one free route cut this bill from $323.55 to $143.55.

тЪая╕П Common mistakes

ЁЯПн In production

On a real account тАФ find the NAT part of the bill, then add the free S3 endpoint to every private route table:

aws ce get-cost-and-usage --time-period Start=2026-08-01,End=2026-09-01 --granularity MONTHLY --metrics UnblendedCost --group-by Type=DIMENSION,Key=USAGE_TYPE --filter '{"Dimensions":{"Key":"SERVICE","Values":["EC2 - Other"]}}'
aws cloudwatch get-metric-statistics --namespace AWS/NATGateway --metric-name BytesOutToDestination --dimensions Name=NatGatewayId,Value=nat-0abc --start-time 2026-09-20T00:00:00Z --end-time 2026-09-27T00:00:00Z --period 86400 --statistics Sum
aws ec2 create-vpc-endpoint --vpc-id vpc-0abc --vpc-endpoint-type Gateway --service-name com.amazonaws.us-east-1.s3 --route-table-ids rtb-private-a rtb-private-b rtb-private-c
resource "aws_vpc_endpoint" "s3" {
  vpc_id            = aws_vpc.main.id
  service_name      = "com.amazonaws.us-east-1.s3"
  vpc_endpoint_type = "Gateway"
  route_table_ids   = [for rt in aws_route_table.private : rt.id]
}

ЁЯПн Why this matters in production: add the S3 and DynamoDB gateway endpoints on day one тАФ they are free тАФ and look at NatGateway-Bytes every month. VPC Flow Logs show which destinations the bytes go to.

тПня╕П Next

The S3 tunnel was one way to skip the gate. There are more тАФ and sometimes the best gate is no gate at all. Alternatives to NAT.

git checkout lesson-07-alternatives
тЖР Previouselastic ipsNext тЖТalternatives

This page is the lesson's README from the lesson-06-costs branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.