Подивився я на costs по інфраструктурі, яка описана в попередньому пості AWS: сетап базової інфраструктури для WordPress, і тяжко зітхнув:
Один NAT Gateway – це чверть витрат на AWS, і навіть маючи AWS Credits мене трошки душить жаба.
Є, звісно, варіант прибрати NAT Gateway зі схеми взагалі:
- можна просто перевести EC2 в Public Subnet: насправді, описаний сетап з використанням AWS Load Balancer дійсно трохи overkill для проекту типу якогось невеликого блогу – але мені все ж хочеться мати “красиву” інфрастуктуру, побудовану “по канонам” та більш наближену до AWS Well-Architected Framework (свідомо без Reliability – тільки одна Availability Zone, та без infrastructure as code – див. AWS Well-Architected Framework Design Principles)
- можна прибрати NAT Gateway взагалі – але залишити EC2 в Private Subnet:
- по факту, в описаному сетапі NAT GW використовується тільки на самому початку, коли встановлюються пакети
nginx,phpта скачується архів з WordPress - але потім, по-перше – треба встановлювати апгрейди із зовнішніх репозиторіїв, по-друге – сам WordPress може ходити в інтернет при запуску своїх cron jobs або робити виклики з плагінів (цікавий приклад є в пості TCP/IP: SYN flood атака на сервер RTFM, та “Hacker News hug of death”, де плагін Page View Count постійно робив запити з серверу RTFM до Cloudflare)
- по факту, в описаному сетапі NAT GW використовується тільки на самому початку, коли встановлюються пакети
Але є і третій варіант – це власний підняти “poor man’s NAT gateway“: просто запустити окремий мінімальний t3.nano EC2, на ньому мати Linux чи FreeBSD, а там налаштувати звичайний NAT.
Бо по суті AWS VPC можна розглядати по аналогії з домашньою мережею, де в ролі NAT Gateway виступає роутер – TP-Link, MikroTik тощо, і цей роутер можна замінити на будь-який ноутбук або ПК з Linux/FreeBSD та налаштувати там NAT з блекджеком і моніторингом.
В коментах до цього поста підсказали про проект fck-nat – вже готовий до використання AWS AMI, до того ж для fck-nat є Terraform модуль terraform-aws-fck-nat.
Зміст
Плюси-мінуси
Звісно, для якогось production сетапу якогось реального проекту простіше і – головне – надійніше мати стандартний AWS Managed NAT Gateway: zero геморою з апгрейдами, zero проблем з availability – за все відповідає AWS.
Якщо ж мати власний NAT Gateway – то це додатковий час на встановлення апгрейдів, моніторинг, ну і якщо такий інстанс впаде – то інстанси в приватних сабнетах залишаться без доступу в Internet.
Ну і якщо робити автоматизацію – то описати з Terraform один чи кілька NAT Gateways набагато простіше, ніж описувати налаштування окремого EC2 – фактично, достатньо просто вказати один параметр у VPC module resource.
Але якщо подивитись на вартість…
А шо по грошам?
Давайте порівняємо вартість AWS Managed NAT Gateway та власного NAT на t3.nano – бо тут є один цікавий нюанс.
NAT Gateway vs t3.nano: per-hour pricing
Перше, і саме відчутне – це погодинна оплата:
- AWS Managed NAT Gateway: $0.048/година – це ~$32 в місяць
- AWS EC2
t3.nano: $0.0059/год – це ~$4.3 на місяць
t3.nano в ролі NAT Gateway для якогось невеликого проекту – з головою: всі операції виконуються в ядрі системи, навантаження на CPU/RAM мінімальне. Єдине. на що варто звертати увагу, це network bandwidth – але для t3.nano маємо до 5 Gbps burst – з запасом, див. Amazon EC2 instance network bandwidth.
NAT Gateway vs t3.nano: per-gigabyte pricing
Другий важливий момент – це вартість трафіку, бо:
- AWS Managed NAT Gateway: тут ми платимо за кожен processed bytes, тобто і ingress (з інтернету – до NAT Gateway – потім всередину VPC), і egress (трафік із VPC в інтернет)
- ціна $0.045/GB
- тут окремо уточню:
- processed bytes рахується для трафіку, який був ініційований з приватного сабнету назовні, тобто коли EC2 робить запит назовні – тоді рахується і запит (egress) і відповідь (ingress)
- трафік, який NAT Gateway отримує ззовні напряму – в мережу не проходить і не рахується, бо NAT GW не приймає вхідних з’єднань
- AWS EC2 instance: платимо тільки за egress
- ціна $0.09/GB
І тут насправді AWS Managed NAT Gateway може бути вигіднішим: якщо у нас трафік переважно out, egress – то ми за нього платимо $0.045, а не $0.09 як при використанні EC2 – у два рази дешевше.
Втім, враховуючи різницю в оплаті per hour, то якщо ми відправляємо менше ~644 GB на місяць – вигода по трафіку AWS Managed NAT Gateway “з’їдається” ціною інстансу:
- різниця вартості AWS Managed NAT Gateway та
t3.nano== $28 на місяць - на кожному переданому у “світ” гігабайті AWS Managed NAT Gateway економить нам $0.045
- $28 / $0.045 приблизно дає 622 GB/міс
Тобто, якщо ми передаємо менше ніж 622 – то за рахунок різниці у вартості інстансів загальна ціна за місяць при використанні власного EC2 з типом t3.nano все одно вийде менша.
Але якщо ми віддаємо в інтернет більше ніж 622 гігабайт – то AWS Managed NAT Gateway стає вигіднішим за рахунок своєї ціни за трафік.
Втім, якщо ми плануємо інфрастуктуру для невеликого веб-сайту чи особистого блогу – що в місяць можна на 622 гігабайт передавати?
Трафік від/до клієнтів піде тільки через ALB, а через NAT Gateway – тільки апгрейди операційної системи та пакетів.
План дій
Отже, що будемо робити:
- запустимо EC2 в публічній мережі
- Security Group:
- дозволяємо тільки out трафік – на вхід з інтернету нічого не має приходити
- дозволяємо весь ingress з Private Subnets – наш EC2 буде передавати дані назовні
- дозволяємо SSH з VPC або користуємось EC2 Instance Connect
- на EC2 маємо якийсь Linux, на якому з
iptablesналаштовуємо NAT - в Route Tables для VPC і Private Subnets налаштуємо default route – 0.0.0.0/0 через Private IP цього EC2
Вибір операційної системи – в принципі, будь-який Linux, тут будемо робити з Amazon Linux, бо дійсно менше геморою ніж з Debian.
Хоча спочатку взагалі думав про FreeBSD – бо FreeBSD традиційно сильна саме в networking, але як вже основний сервер для самого блогу на Amazon Linux, то не буду розводити зоопарк.
На Amazon Linux 2023 по-дефолту встановлений nftables – але iptables теж є як wrapper, встановлюється з репозиторію окремим пакетом.
Створення NAT Gateway Security Group
Переходимо в VPC, додаємо нову групу:
Створення EC2
Задаємо ім’я, вибираємо операційну систему, тут буде Amazon Linux:
Вибираємо тип інстансу, вибираємо або створюємо ключ для SSH:
В Network settings вибираємо VPC, в Subnet вказуємо той, в якому “main EC2” з блогом – аби уникнути cross Availability Zone traffic (див. Overview of Data Transfer Costs for Common Architectures), та включаємо Auto-assign public IP – бо NAT Gateway повинен мати Public IP, на який буде отримувати пакети від клієнтів в інтернеті:
Тут все – запускаємо створення інстансу.
Після старту робимо важливу зміну в його налаштуваннях – треба виключити перевірку Source/Destination check: вона вказує EC2 приймати і відправляти тільки той трафік, де source або destination співпадає з його власним IP.
Для NAT це треба вимкнути, бо NAT instance по визначенню пересилає чужий трафік, де ні source, ні destination не є його власним IP:
Задаємо Stop:
Налаштування Linux в ролі NAT Gateway
Підключаємось до EC2 (EC2 Instance Connect робили в попередньому пості):
[setevoy@setevoy-work ~] $ aws --region eu-west-1 --profile setevoy ec2-instance-connect ssh --instance-id i-0e54f36ce6bb90da4 --connection-type eice ... [ec2-user@ip-10-0-1-79 ~]$
Перевіряємо параметр net.ipv4.ip_forward, який задає ядру системи дозвіл на пересилання пакетів між мережевими інтерфейсами – саме це і є основою будь-якого NAT і роутингу:
[ec2-user@ip-10-0-1-79 ~]$ sysctl net.ipv4.ip_forward net.ipv4.ip_forward = 0
0 – відключений, вмикаємо його:
[ec2-user@ip-10-0-1-79 ~]$ sudo sysctl -w net.ipv4.ip_forward=1 net.ipv4.ip_forward = 1
Зміни з sysctl -w застосовуються зараз, але після перезавантаження системи зникнуть, тому додаємо в конфіг /etc/sysctl.conf:
[ec2-user@ip-10-0-1-79 ~]$ echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf net.ipv4.ip_forward = 1
Перечитуємо конфіг, застосовуємо зміни:
[ec2-user@ip-10-0-1-79 ~]$ sudo sysctl -p net.ipv4.ip_forward = 1
Перевіряємо ще раз:
[ec2-user@ip-10-0-1-79 ~]$ sysctl net.ipv4.ip_forward net.ipv4.ip_forward = 1
Налаштування iptables та MASQUERADE
Можна зробити з nftables, але iptables частіше зустрічається, та і більш звично.
Детальніше про iptables писав ще у 2014 році (OMG!), див. Linux: IPTABLES – руководство: часть 1 – основы IPTABLES – кардинальних змін в основах не було, хоча сам iptables вже поступово замінюється на nftables.
Перевіряємо імена інтерфейсів:
[ec2-user@ip-10-0-1-79 ~]$ ip a s 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 ... 2: enX0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc fq_codel state UP group default qlen 1000 ...
Встановлюємо пакет iptables:
[ec2-user@ip-10-0-1-79 ~]$ sudo dnf install -y iptables
Додаємо правило:
[ec2-user@ip-10-0-1-79 ~]$ sudo iptables -t nat -A POSTROUTING -o enX0 -j MASQUERADE
Тут:
-t nat: вносимо зміни в таблицюnat-A POSTROUTING: додаємо правило вPOSTROUTINGchain – тобто правило спрацьовує після того, як ядро вже вирішило куди відправити пакет – але ще не відправило отримувачу-o enX0: правило тільки для пакетів що виходять через інтерфейсenX0(наш публічний інтерфейс)-j MASQUERADE: підміняємо source IP пакету (Private IP інстансу EC2, на якому буде блог) на IP інтерфейсуenX0– публічний IP нашого інстансу EC2 з NAT Gateway
Перевіряємо правила:
[ec2-user@ip-10-0-1-79 ~]$ sudo iptables -t nat -L POSTROUTING -n -v
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE all -- * enX0 0.0.0.0/0 0.0.0.0/0
Аби правило зберігалось при рестартах інстансу – додаємо (вже має бути) пакет iptables-services, зберігаємо правила у файл /etc/sysconfig/iptables:
[ec2-user@ip-10-0-1-79 ~]$ sudo dnf install -y iptables-services [ec2-user@ip-10-0-1-79 ~]$ sudo service iptables save [ec2-user@ip-10-0-1-79 ~]$ sudo systemctl enable iptables
Зміни в AWS VPC Route Tables
У нас є окремі таблиці маршрутизації на кожну Private Subnet:
В яких зараз маршрут до інтернету, тобто 0.0.0.0/0, заданий через AWS Managed NAT Gateway:
Додаємо нове правило, вказуємо новий EC2 інстанс:
Видаляємо маршрут через NAT gateway – тут можливий короткий downtime, бо активні підключення із VPC в інтернет будуть розірвані:
Повторюємо зміни для обох Route Tables, і перевіряємо.
Підключаємось на EC2, дивимось результат ifconfig.me – і отримуємо Public IP нашого нового self-managed NAT Gateway:
[ec2-user@ip-10-0-3-146 ~]$ curl -s ifconfig.me 108.130.182.54
Власне, на цьому і все.
Можна видаляти AWS Managed NAT Gateway:
Bonus: Amazon Linux auto-upgrades
Ну і аби не ходити на інстанс з ручними апгрейдами – налаштуємо аналог unattended-upgrades з Debian.
В RHEL/CentOS/Fedora/Amazon Linux це пакет dnf-automatic:
[ec2-user@ip-10-0-1-79 ~]$ sudo dnf install -y dnf-automatic
Редагуємо конфіг /etc/dnf/automatic.conf, мінімально – задаємо apply_updates = yes.
В upgrade_type можна задати security, а не встановлювати всі – бо це все ж gateway:
... # default = all available upgrades # security = only the security upgrades upgrade_type = security ... apply_updates = yes ... [email] # TODO in the following rtfm.co.ua posts about setting up AWS
Про відправку email з AWS EC2 інстансів може буду писати окремо в частині по налаштуванню AWS Simple Email Service.
Додаємо запуск по крону за розкладом:
[ec2-user@ip-10-0-1-79 ~]$ sudo systemctl enable --now dnf-automatic.timer Created symlink /etc/systemd/system/timers.target.wants/dnf-automatic.timer → /usr/lib/systemd/system/dnf-automatic.timer.
Готово.
![]()











