[AWS Infra] Building & Configuring a NAT Instance to Cut NAT Gateway Costs (Part 2)
Overview: Building a NAT Instance on AWS (cost saving)
- Why a NAT Instance (instead of a NAT gateway) (Part 1)
- How to use the NAT Instance AMI provided on AWS (Part 1)
- Building a NAT Instance directly with iptables (Part 2)
In Part 1, I built a NAT Instance using the NAT Instance AMI provided by the AWS Community. However, that AMI has the downside of being hard to maintain due to issues like an end-of-service OS version. So in this Part 2 post, I'll configure a NAT Instance directly by manipulating iptables on the latest OS that AWS provides directly.
Since I already covered the network diagram I built in Part 1, I'll just briefly explain the situation and move on.
To let a private network (Private subnet) communicate with the internet, you need a NAT Gateway. (Because the public IP must be translated to the private IP for communication to be possible inside the private network: the router role.) Among the services AWS provides there is a NAT gateway, but to cut costs I built a NAT Instance directly, and Part 2 explains how to configure a base OS — one where the NAT Instance hasn't been set up — to perform the NAT role.
How to build a NAT Instance (EC2)
1. Create a basic EC2
Figure 1. NAT Instance EC2 creation
I use the AMI (LTS version) that AWS itself prominently features, not the community one. I tend to like Ubuntu, so I chose Ubuntu (24.04 LTS). The NAT Instance must of course be placed in the public subnet, and the other routing table examples are all posted in Part 1.
2. Manipulating iptables on the EC2 OS (configuring it as a NAT Instance)
SSH into the NAT Instance created above. Then follow the procedure below.
1. Enable IP forwarding
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
This is the process of enabling IP forwarding on a Linux server. Since the NAT Instance must route network traffic somewhere other than itself, it has to allow the path for packets to come in and go out.
Briefly analyzing the command line above:
net.ipv4.ip_forward = 1is the setting that enables the IP forwarding function./etc/sysctl.conf: permanently sets the forwarding setting added to sysctl.conf above.sudo sysctl -p: applies the setting above immediately.
Figure 2. the /etc/sysctl.conf file viewed in an editor
Alternatively, if you open sysctl.conf in an editor, you'll see that net.ipv4.ip_forward=1 is disabled with a # as in the figure above. You can simply uncomment that part and apply the setting.
2. iptables NAT configuration
sudo iptables -t nat -A POSTROUTING -o {your ethernet} -j MASQUERADE
This implements the NAT function so that the private network's IP is translated to the NAT Instance's public IP. The explanation of each option is as follows.
-t nat: adds the rule to the NAT table.-A POSTROUTING: performs NAT processing after the packet is routed (just before departure). (when coming in from the external network to the private network)-o {your eth}: applies the rule to traffic going out through your eth (e.g., eth0, ens5) interface. (this means the public network interface)-j MASQUERADE: translates the source IP to the NAT Instance's public IP. (i.e., when going out from the private network to the internet)
How to check your network interface name (using ip addr) : using ifconfig is fine too (possible after installing netstat from apt)
ip addr
Figure 3. result of checking the network interface name
Using ip addr / ifconfig, you can find the network interface name as in Figure 3. In the figure above, you can see that ens5 is shown as the network name.
3. Verify the iptables result
Once applied above, you have to go through the process of checking whether it was applied properly.
sudo iptables -t nat -L -n -v
The command above is a command line that shows you the NAT tables applied in iptables. The explanation of the options is below.
-t nat: checks the NAT table.-L: lists all chains and rules.-n: shows IP addresses instead of host names.-v: additionally shows detailed info (packet count, bytes, etc.).
Figure 4. result of adding a rule to iptables (top: before, bottom: after)
As in Figure 4, the MASQUERADE rule should be added to the POSTROUTING chain. Once you've confirmed that result, you now have to configure it so the setting persists even after a reboot.
4. Save the iptables settings / rules (to keep the settings after reboot)
sudo apt-get update
sudo apt-get install -y iptables-persistent
To get the latest version, run apt-get update first, then install. To keep the iptables rules even after a system reboot, install the iptables-persistent package. Think of iptables-persistent as a utility that saves the iptables rules and automatically loads them at boot. During installation it asks whether to save the currently set iptables rules; just say yes to everything.
sudo netfilter-persistent save
This saves the currently set iptables rules. netfilter-persistent saves iptables and related rules to a file such as /etc/iptables/rules.v4. The saved rules are kept even after the system reboots.
sudo systemctl enable netfilter-persistent
This enables the netfilter-persistent service so that the iptables rules are automatically loaded even after a system reboot.
This wraps up the NAT-Instance setup at the OS level. For the rest, as covered in Part 1, configure the private routing table and the source/destination check setting on the AWS EC2. (Please refer to the part "2) Configuring the Private subnet Routing Table and settings in the NAT Instance console" in the Part 1 post.)
3. Result (confirming the Private subnet's internet connection)
Figure 5. NAT Instance build result
After finishing the settings above, if you go into the EC2 in the Private Subnet and run sudo apt-get update, you'll be able to confirm that the internet is connected as shown above.
Closing
In this Part 2 post, I just configured and set up directly at the OS level the NAT Instance that the AMI Community provides. The rest — the routing table configuration, the EC2 destination check in the console, etc. — are all the same as in the Part 1 post. Since I had to make it able to serve all three roles of Reverse Proxy / NAT Instance / Bastion, I configure and use it directly on a version-managed OS as above.
📦 Migrated from the Tistory blog I used to run. Original: taehyuklee.tistory.com/28
![[AWS Infra] Building & Configuring a NAT Instance from an AMI to Cut NAT Gateway Costs (Part 1)](assets/posts/nat-instance-build-1/cover.webp)
Comments