Ravindra BagaleCourses & study guides मराठी Track your progress

Chapter 15: Amazon VPC — Subnets, Route Tables, NACL, NAT Gateway and Bastion Host

15.10 Project: build the 3-tier network and launch the servers

Come on, now the real project! A small "students list" website: the Nginx web server in a public subnet, the PHP-FPM app server in a private subnet, and the MySQL database in another private subnet. When you open the page in the browser, the request travels across three servers and the data from the database comes back. So the very first job – get the network and servers ready.

The finished project looks like this:

   Browser (HTTP 80)            You (SSH 22)
          |                          |
          v                          v
   [ Internet gateway: society-igw ]
          |
+------------ society-vpc 10.0.0.0/16 ------------+
| web-public-1a 10.0.1.0/24   public-rt -> IGW    |
|   web: Nginx 10.0.1.10    bastion 10.0.1.20     |
|   NAT gateway + Elastic IP                      |
|        | fastcgi 9000         ^ outbound only   |
| app-private-1a 10.0.2.0/24  private-rt -> NAT   |
|   app: PHP-FPM 10.0.2.10                        |
|        | MySQL 3306                             |
| db-private-1a 10.0.3.0/24   private-rt -> NAT   |
|   db: MariaDB 10.0.3.10                         |
+-------------------------------------------------+

Step 1 — Network

Build it as in the earlier lessons:

  1. society-vpc 10.0.0.0/16 with DNS hostnames on (15.2).
  2. Subnets web-public-1a 10.0.1.0/24 (auto-assign public IPv4 on), app-private-1a 10.0.2.0/24, db-private-1a 10.0.3.0/24, all in ap-south-1a (15.3).
  3. society-igw attached to the VPC (15.5).
  4. public-rt with 0.0.0.0/0 → IGW for the public subnet; private-rt for both private subnets (15.6).
  5. society-nat in web-public-1a with an Elastic IP, and 0.0.0.0/0 → NAT in private-rt (15.9). The private servers need it to install packages.

Keep the VPC's default network ACL (it allows all traffic); the security groups below do the precise work.

Step 2 — Security groups (the chain)

Create them in this order in EC2 → Security Groups → Create security group, with VPC society-vpc, because each one refers to the one before it:

Security group Inbound rule Source Why
bastion-sg SSH TCP 22 My IP Only you can reach the bastion
web-sg HTTP TCP 80 0.0.0.0/0 Visitors
web-sg HTTPS TCP 443 0.0.0.0/0 Visitors, once you add a certificate
web-sg SSH TCP 22 bastion-sg Admin access only through the bastion
app-sg Custom TCP 9000 web-sg Only Nginx may talk to PHP-FPM
app-sg SSH TCP 22 bastion-sg Admin access
db-sg MySQL/Aurora TCP 3306 app-sg Only the app server may talk to MySQL
db-sg SSH TCP 22 bastion-sg Admin access

Leave the outbound rules at the default (all traffic allowed). Using a security group as the source means "any instance that carries that group", so the rules keep working when private IPs change.

Step 3 — Launch four instances

Create a key pair society-key (EC2 → Key pairs), keep society-key.pem safe on your laptop and run chmod 400 society-key.pem. Then launch four Amazon Linux 2023 instances with a small free-tier eligible type such as t3.micro or t2.micro. In the launch wizard, open Network settings → Edit:

Name VPC Subnet Auto-assign public IP Security group
bastion society-vpc web-public-1a Enable bastion-sg
web society-vpc web-public-1a Enable web-sg
app society-vpc app-private-1a Disable app-sg
db society-vpc db-private-1a Disable db-sg

Step 4 — Write down the private IPs

AWS picks the private IPs from each subnet. This chapter uses these example values; replace them with yours in every command and config file that follows:

Server Example private IP Public IP
web 10.0.1.10 <WEB_PUBLIC_IP>
bastion 10.0.1.20 <BASTION_​PUBLIC_​IP>
app 10.0.2.10 none
db 10.0.3.10 none

Step 5 — First check: reach every server through the bastion

On your laptop:

ssh-add society-key.pem
ssh -J ec2-user@<BASTION_PUBLIC_IP> ec2-user@10.0.1.10     # web
ssh -J ec2-user@<BASTION_PUBLIC_IP> ec2-user@10.0.2.10     # app
ssh -J ec2-user@<BASTION_PUBLIC_IP> ec2-user@10.0.3.10     # db

Each one should end at a prompt such as [ec2-user@ip-10-0-2-10 ~]$. On app and db, run curl -s https://checkip.amazonaws.com: it prints the NAT gateway's Elastic IP, so package installs will work.

Ravindra Bagale's Tip

The order matters when you create the security groups: first bastion-sg, then web-sg, then app-sg, and db-sg last – because each group uses the previous one as its source. Many students put an IP like 10.0.1.10/32 as the source; when a server is replaced the IP changes and the project breaks. Choose the security group as the source. A rock-solid design!

Lab

Chala, build the network, the four security groups and the four instances. Fill in the private IP table with your own values, and connect to all three servers with ssh -J before you go on.