[AWS] Cutting NAT Gateway Costs — Building a NAT Instance from an AMI (Part 1)

Overview — Building a NAT Instance (Cost Saving)

  1. Why a NAT Instance (instead of a NAT Gateway) — Part 1
  2. Using the AWS-provided NAT Instance AMI — Part 1
  3. Building a NAT Instance manually with iptables — Part 2

In Part 1 we use the NAT Instance AMI provided by the AWS community. To build a NAT Instance manually with iptables, see Part 2.

[AWS] Cutting NAT Gateway Costs — Building a NAT Instance with iptables (Part 2)
The Part 1 community AMI runs an old (EOS) OS and is hard to maintain. In Part 2 we build a NAT instance on the latest Ubuntu by configuring iptables directly (IP forwarding + MASQUERADE), and persist the rules across reboots.
taystudios.com/blog

NAT Gateway & NAT Instance?

While handling network/application architecture on AWS, the network diagram I drew looks like this.

Architecture connecting a Private Subnet to the internet via a NAT Instance (EC2) instead of a NAT Gateway Figure 1. Connecting a Private Subnet to the internet with a NAT Instance (EC2) instead of a NAT Gateway

Normally a Private Subnet needs a NAT Gateway to talk to the internet. But in this setup, instead of placing a separate NAT Gateway in the Public Subnet, I used an EC2 (NAT Instance) to connect the Private Subnet to the internet while it also serves as a Reverse Proxy and a Bastion server.

The pros and cons of a NAT Instance:

Pros

  • You avoid the NAT Gateway, reducing cost. If you're going to run a Proxy/Bastion server anyway, the idea is to route internet traffic through that server.

Cons

  • If the Proxy server shuts down or misbehaves, the Private Subnet loses internet. (Architecturally, if the Proxy dies the downstream services can't be served anyway, which I judged acceptable.)
  • It doesn't guarantee the high availability, scalability, security, and patch management of an AWS NAT Gateway — you manage the OS version and security yourself. (This is essentially why people use a NAT Gateway.)

Despite the cons, I built a NAT Instance because the project scale wasn't large and, above all, I had to cut costs. (A NAT Gateway is roughly $32/month base + traffic charges.)

There are two main ways to create a NAT Instance on AWS.

Method 1. Using the AWS community AMI

1) Create a NAT Instance from the AMI

Selecting 'Browse more AMIs' in the EC2 launch screen Figure 2. Select 'Browse more AMIs' in the EC2 launch screen

In the EC2 launch screen, click 'Browse more AMIs.'

Searching amzn-ami-vpc-nat in the Community AMIs tab Figure 3. Searching in the Community AMIs tab

In the Community AMIs tab, search for amzn-ami-vpc-nat. The registered AMIs differ per region; in the Seoul region several appear. I picked the one with the most recent publish date.

Launching an EC2 (NAT Instance) from the selected NAT AMI Figure 4. Launching the NAT Instance

When you select the AMI, Figure 4 shows the CPU architecture (here x86_64), storage format, etc. that match the AMI, and you can pick an instance type. An EC2 launched this way is already configured to pass incoming traffic on to another destination (i.e., it acts as a NAT Gateway).

Note: For SSH, the username is shown as ec2-user as in Figure 4.

Place the EC2 in your VPC's Public Subnet. The Public Subnet's route table must of course be connected to an Internet Gateway and allow VPC-internal local traffic. I recommend setting security via security groups and NACLs. (Basic AWS concepts are only mentioned, not detailed, here.)

Public Subnet route table (connected to the Internet Gateway) Reference. Public Subnet route table — must connect to the Internet Gateway for external communication

2) Private Subnet routing & NAT Instance console settings

With a NAT Gateway, you'd also connect it in the Private Subnet's route table. A NAT Instance needs the same.

Setting the target to the NAT instance in the Private Subnet route table Figure 5. Private Subnet route table setup

In the Private Subnet route table, set the target to 'Instance' and select the NAT Instance you created (e.g., nat-instance). This means all internet-bound traffic from the Private Subnet goes through the NAT Instance.

Target mapped to an ENI (network card) starting with eni- Reference. Network card (ENI) mapping

After setup, the target starts with eni-, an Elastic Network Interface that maps directly to a network card resource. You can infer that the OS forwards traffic to another destination through Layer 2 (data link) and Layer 3 (network). (The community AMI has this configured.)

Now change the EC2 instance setting itself. In the EC2 dashboard, click nat-instance → top-right 'Actions' → 'Networking' → 'Change source/destination check.' (Besides the route table, you must also change the instance setting.)

NAT instance Actions > Networking > Change source/destination check menu Figure 6. Changing NAT Instance networking settings

Selecting 'Stop' for the source/destination check Figure 7. Source/destination check — select 'Stop'

As in Figure 7, select 'Stop' for the source/destination check. AWS drops traffic that doesn't reach the target EC2, so to route traffic through one instance to another you need this setting.

Required — the default security group usually only opens SSH. Configure the security group to at least allow communication.

Private EC2 security group inbound settings Reference. Private EC2 security group (allow-all traffic as an example)

Here, for demonstration, I set the Private Subnet EC2's security group to allow all traffic. In practice, configure it per your project policy.

I also did not set an Elastic IP this time; even without an EIP, as long as the NAT Instance's public IP is enabled, a random IP is attached. By DHCP policy the public IP changes if you stop/start the EC2, but if you keep it running, it's fine without an EIP.

Result of building the NAT Instance

Before connecting the NAT Instance — apt-get update fails Figure 8. Before connecting the NAT Instance

After connecting the NAT Instance — apt-get update works Figure 9. After connecting the NAT Instance

Before connecting, sudo apt-get update can't update the Debian-family apt repositories; after connecting, it downloads normally.

Wrap-up

Using the AWS community NAT instance AMI, you can build a NAT instance with little configuration. But this AMI uses an old OS version and is end-of-service (EOS). It's hard to find files for manual package downloads and support sites are limited, so maintenance is very difficult and it's hard to use for anything beyond NAT.

Since I wanted to also use the NAT instance as a Reverse Proxy server, OS version management matters. At minimum it needs certificate packages for HTTPS, which this AMI didn't support. So in Part 2, I build a NAT instance directly on the latest AWS OS.

[AWS] Cutting NAT Gateway Costs — Building a NAT Instance with iptables (Part 2)
The Part 1 community AMI runs an old (EOS) OS and is hard to maintain. In Part 2 we build a NAT instance on the latest Ubuntu by configuring iptables directly (IP forwarding + MASQUERADE), and persist the rules across reboots.
taystudios.com/blog

📦 Migrated from my own Korean blog (my own writing). Original: taehyuklee.tistory.com/27

Share𝕏f

Comments