Sitemap

Custom VPC + Bastion Host + Apache Web Server (AWS)

7 min readSep 13, 2025

Modern cloud networks need secure entry points and clear traffic flow. In this hands-on lab, you will design a custom VPC, deploy a bastion host for secure SSH access, run an Apache Web Server in the public subnet, optionally add a private EC2, and validate NAT connectivity — then clean everything up.

Press enter or click to view image in full size

Before You Start: Key Concepts

What is a VPC (Virtual Private Cloud)?

A VPC is your logically isolated network in AWS. You choose the IP range (CIDR), create subnets (public/private), attach gateways, define route tables, and control traffic with security groups and NACLs.

Internet Gateway (IGW)

An Internet Gateway is a horizontally scaled, highly available AWS component that allows resources in public subnets to reach the internet. A subnet becomes “public” when its route table has a default route 0.0.0.0/0 pointing to the IGW.

NAT Gateway

A NAT Gateway lets instances in private subnets initiate outbound internet connections (e.g., to download packages) without exposing those instances to inbound traffic from the internet. Private subnet route tables point 0.0.0.0/0 to the NAT (which lives in a public subnet).

Bastion Host (Jump Host)

A bastion host is a hardened EC2 instance in a public subnet used as a single, controlled SSH entry point to reach private resources. Instead of opening SSH to the world on every server, you lock SSH to the bastion and then jump (ProxyJump) from there into private hosts.

🎯 Goal

  • Create a custom VPC with public and private subnets
  • Attach an Internet Gateway and deploy a NAT Gateway
  • Configure route tables for correct egress
  • Create security groups for bastion / web / private instances
  • Launch a Bastion Host (public) and a Web Server (public)
  • (Optional) Launch a Private EC2 and test outbound via NAT
  • Validate access paths and clean up resources

1️⃣ Create VPC and Subnets

AWS Console → VPC → “Create VPC”

  • Vpc Settings: VPC only
  • Name tag: Workshop-VPC
  • IPv4 CIDR block: 10.0.0.0/16
Press enter or click to view image in full size

Subnets

Public Subnet

Subnets→Create Subnet

  • VPC ID: Workshop-VPC
  • Subnet Name: Public Subnet A
  • Availability Zone: us-east-1a
  • IPv4 subnet CIDR block: 10.0.1.0/24
Press enter or click to view image in full size

Private Subnet

Subnets→Create Subnet

  • VPC ID: Workshop-VPC
  • Subnet Name: Private Subnet A
  • Availability Zone: us-east-1b
  • IPv4 subnet CIDR block: 10.0.2.0/24
Press enter or click to view image in full size

2️⃣ Internet Gateway (IGW) & NAT Gateway

Internet Gateway

VPC→Internet gateways→Create internet gateway

Internet gateway settings:

Name: Workshop-IGW

Press enter or click to view image in full size

Attach the Internet Gateway to the VPC (Workshop-VPC)

Select internet gateway →ActionsAttach to VPC

Press enter or click to view image in full size
Press enter or click to view image in full size
Press enter or click to view image in full size

NAT Gateway

VPC→NAT gateways→Create NAT gateway

  • Name: Workshop-NAT
  • Subnet: Public Subnet A
  • Connectivity type: Public
  • Elastic IP allocation ID: Allocate Elastic IP
Press enter or click to view image in full size
Press enter or click to view image in full size

Result

  • Public subnet egress → IGW
  • Private subnet egress → NAT Gateway

3️⃣ Route Tables

Public Route Table

VPC →Route tables→Create route table

  • Name: Public-RT
  • VPC: Workshop-VPC
Press enter or click to view image in full size

Add Route

Select Public-RT→Routes→Edit routes–Add route

  • Destination: 0.0.0.0/0
  • Target: internet Gateway(Workshop-IGW)
Press enter or click to view image in full size

Associate with Public Subnet A

Public-RT→Subnet associations→Edit subnet associations→Select Public subnet A

  • Available subnets: Public subnet A
Press enter or click to view image in full size

Private Route Table:

VPC →Route tables→Create route table

  • Name: Private-RT
  • VPC: Workshop-VPC
Press enter or click to view image in full size
Press enter or click to view image in full size

Route Add

Select Private-RT→Routes→Edit routes–Add route

  • Destination: 0.0.0.0/0
  • Target: NAT Gateway(Workshop-NAT)
Press enter or click to view image in full size

Associate with Private Subnet A

Select Private-RT→Subnet associations→Edit subnet associations→Select private subnet A

  • Available subnets: Private subnet A
Press enter or click to view image in full size

4️⃣ Security Groups

VPC→Security→Security groups→Create Security Group

SG-Bastion

  • Security group name: SG-Bastion
  • Description: SG-Bastion
  • VPC: Workshop-VPC

Inbound rules:

  • Type: SSH
  • Protocol: TCP
  • Port range: 22
  • Source:0.0.0.0/0
Press enter or click to view image in full size

SG-Web

  • Security group name: SG-Web
  • Description: SG-Web
  • VPC: Workshop-VPC
  • Inbound: 80/tcp → 0.0.0.0/0
  • Inbound: 22/tcp → SG-Bastion
Press enter or click to view image in full size

5️⃣ Bastion Host (Public Subnet)

EC2→Instances→Launch an instance

  • Name and tags: Bastion
  • AMI→ Amazon Linux 2023, t3.micro
Press enter or click to view image in full size
  • Key Pair (login):
  • Create new key pairKey pair name: ec2_ssh_key
  • Type: RSA, File format: .pem → Create
Press enter or click to view image in full size

Network settings → Edit:

  • VPC: Workshop-VPC
  • Subnet: Public subnet A
  • Auto-assign public IP: Enable
  • Firewall (SG): Select security group
  • Security group name: SG-Bastion
Press enter or click to view image in full size
Press enter or click to view image in full size

SSH Test

Use the bastion’s public IP to connect over SSH, for example: ssh -i ec2_ssh_key.pem ec2-user@<BASTION_PUBLIC_IP>

chmod 400 ec2_ssh_key.pem
ssh -i ec2_ssh_key.pem ec2-user@44.212.21.106
Press enter or click to view image in full size

6️⃣ Web Server (Public Subnet)

EC2→Instances→Launch an instance

  • Name and tags: Web
  • AMI→ Amazon Linux 2023, t3.micro
Press enter or click to view image in full size
Press enter or click to view image in full size

Network settings → Edit:

  • VPC: Wokshop-VPC
  • Subnet: Public subnet A
  • Auto-assign public IP: Enable
  • Firewall (SG): Select security group
  • Security group name: SG-Web
Press enter or click to view image in full size

Advanced details:

User data

#!/bin/bash
sudo dnf update -y
sudo dnf install httpd -y
systemctl start httpd
systemctl enable httpd
echo "<html><h1>Welcome to Tech Istanbul: Apache Web Server</h1></html>" > /var/www/html/index.html
Press enter or click to view image in full size

Click on Launch instance button.

Press enter or click to view image in full size

Validate in browser

http://<WEB_PUBLIC_IP>
Press enter or click to view image in full size

SSH Test Connection

ssh -i ec2_ssh_key.pem ec2-user@3.82.122.163

Press enter or click to view image in full size

SSH directly to Web from the internet should fail by design (22 allowed only from SG-Bastion).

We’ll SSH to the web server through the bastion host, targeting its private IP address (not the public IP)

ssh -i ec2_ssh_key.pem \
-o 'ProxyCommand=ssh -i ec2_ssh_key.pem -W %h:%p ec2-user@44.212.21.106' \
ec2-user@10.0.1.15
Press enter or click to view image in full size

7️⃣ Private EC2

EC2→Instances→Launch an instance

  • Name and tags: private-EC2
  • AMI→ Amazon Linux 2023, t3.micro
Press enter or click to view image in full size

Network settings → Edit:

  • VPC: Wokshop-VPC
  • Subnet: Private subnet A
  • Auto-assign public IP: disable
  • Firewall (SG): Select security group
  • Security group name: SG-private
  • Inbound: 22/tcp → SG-Bastion
Press enter or click to view image in full size

Click on Launch instance button

Press enter or click to view image in full size

🔐 To connect Private-EC2 SSH via Bastion

ssh -i ec2_ssh_key.pem \
-o 'ProxyCommand=ssh -i ec2_ssh_key.pem -W %h:%p ec2-user@44.212.21.106' \
ec2-user@10.0.2.190
Press enter or click to view image in full size

NAT Gateway Validation (Private EC2)

  1. On Private-EC2, install a package:
sudo yum install nginx
Press enter or click to view image in full size

Should succeed (egress via NAT). nginx installed.

Now remove the 0.0.0.0/0 → NAT route from Private-RT and try again:

VPC →Route tables→PrivateRT→Edit routes

Press enter or click to view image in full size

Now install a package

sudo dnf install httpd
Press enter or click to view image in full size

This should fail (no internet). Restore the NAT route afterwards.

🧹 Cleanup

  1. Terminate EC2 instances (Bastion, Web, Private if created)
  2. Delete NAT Gateway
  3. Release Elastic IP
  4. Delete the VPC

--

--

No responses yet