Networking is the foundation of everything you build in the cloud. Before you can run a web server, store a file, or host a database, you need a place for it to live and a way for it to communicate.

In this post, we are going to break down the physical reality of the cloud, explain the core concepts of AWS networking in plain English, and finally, build a working network from scratch using the AWS Command Line Interface (CLI).

The Physical Reality: What is the Cloud? Link to heading

People often talk about “the cloud” as if it’s a magical, invisible entity. In reality, the cloud is essentially a vast network of world-class data centers that you can tap into over the internet. The core business of a cloud vendor such as Amazon Web Services (AWS) is leasing out this massive computing power (like virtual servers) and managed services (like databases) to organizations. Instead of a company spending millions of dollars buying their own hardware, managing temperature-controlled server rooms, and paying hefty electric bills, they simply rent exactly the capacity they need from AWS by the minute.

To make this possible, AWS builds and maintains massive, highly secure, interconnected data centers all over the world. When you click a button in AWS, you are spinning up resources inside one of these very real physical buildings.

The Global Infrastructure: Where Does Your Code Live? Link to heading

When you deploy something on AWS, you have to choose where it goes. AWS divides its physical infrastructure into three main concepts:

1. Regions Link to heading

A Region is a physical, geographic location in the world (like Northern Virginia, London, or Tokyo). You usually choose a region closest to your customers so your website loads faster.

2. Availability Zones (AZs) Link to heading

Inside every Region are multiple Availability Zones (usually 3 or more). An AZ is one or more discrete data centers with redundant power, networking, and connectivity.

  • Why do we need AZs? If a storm knocks out power to one data center (one AZ), your application can stay online because it is also running in a second data center (another AZ) miles away.

3. Edge Locations Link to heading

These are smaller data centers located even closer to end-users (in hundreds of cities globally). They are mainly used to cache (temporarily store) static content like images and videos so they load instantly for users, no matter where they are in the world.

Core Networking Concepts: The Virtual Private Cloud Link to heading

Now that we know the physical layout, let’s look at the virtual network you will build on top of it.

What is a VPC? Link to heading

A VPC (Virtual Private Cloud) is your own logically isolated section of the AWS cloud. Think of it as your own private virtual data center. When you create a VPC, you draw a virtual fence around your slice of the AWS infrastructure.

Subnets: Dividing the Network Link to heading

A Subnet is a smaller chunk of your VPC. You use subnets to organize your resources. Subnets are tied to a specific Availability Zone. There are two main types:

  • Public Subnet: Has direct access to the internet. You put things here that the public needs to see, like a web server or a public load balancer.
  • Private Subnet: Has no direct access to and from the internet. You put sensitive things here, like your customer database.

The Gateways & Routing Link to heading

How does traffic actually flow in and out of your VPC?

  • Internet Gateway (IGW): This is the front door to your VPC. It allows in and out communication between your network and the outside internet.
  • Route Tables: This is the rulebook. It tells network traffic where it is allowed to go.
  • NAT Gateway: What if a database in your private subnet needs to download a security update from the internet? A NAT Gateway allows private instances to reach out to the internet, while blocking the internet from reaching in.
  • Security Groups: Think of these as the bouncers for your servers. They are virtual firewalls attached directly to your instances that dictate exactly what traffic is allowed in (like SSH or HTTP) and what is allowed out.

Accessing Your Servers: SSH and Key Pairs Link to heading

Once your virtual servers are running, how do you actually log into them?

  • SSH (Secure Shell): This is a standard network protocol used to securely connect to a remote server over the internet. It gives you a command-line terminal to remotely control your EC2 instance.
  • Key Pairs: Instead of using a vulnerable password, AWS uses cryptography to verify your identity. Think of a key pair like a lock and a key. The public key is given to AWS (who installs it as the “lock” on your server), and the private key is a file you download to your computer (your physical “key”). You must have the private key file on your machine to log in.

What We Are Building Link to heading

Before we dive into the command line, here is a visual map of the network architecture we are about to build. Notice how the region contains the VPC, which contains the Subnets, and how traffic flows from the outside internet all the way down to our servers.

Visual representation of a VPC and its associated resources

Visual representation of a VPC and its associated resources

Hands-On Tutorial: Building & Testing a VPC with the AWS CLI Link to heading

Let’s put this blueprint into practice. We are going to build a VPC with one public subnet, one private subnet, and deploy an EC2 server in each. Finally, we’ll prove the network works.

After creating each resource, we will store its ID (a string that identifies that resources within AWS) to be used in subsequent command. Here I provide the commands for Unix-like systems, if you’re using Windows adapt the command to the correct syntax. Also make sure to replace the YOUR_*_ID with the actual value from the output of the creation command.

Prerequisite: You need an AWS account and the AWS CLI installed and configured on your computer.

Important: When you’re done with the steps or want to step out from your computer for several hours, don’t forget to follow the cleanup steps to prevent being charged for unused resources

Step 1: Create the VPC Link to heading

To start, we’ll carve out our virtual data center by assigning it a primary block of IP addresses (known as a CIDR block).

# Creates a VPC with a /16 block, providing over 65,000 available IP addresses
aws ec2 create-vpc --cidr-block 10.0.0.0/16

Take note of the VpcId that is returned in your terminal. You will need it for the next steps!

# save the VPC id to an environment variable
VPC_ID=YOUR_VPC_ID

Step 2: Create the Subnets Link to heading

Next, we divide our VPC into two smaller networks. We’ll specify the VPC ID, the smaller IP range for the subnet, and the specific Availability Zone we want to use.

# 1. Create the Public Subnet using a smaller /24 block
aws ec2 create-subnet \
  --vpc-id $VPC_ID \
  --cidr-block 10.0.1.0/24 \
  --availability-zone us-east-1a

# 2. Create the Private Subnet using a different /24 block in the same zone
aws ec2 create-subnet \
  --vpc-id $VPC_ID \
  --cidr-block 10.0.2.0/24 \
  --availability-zone us-east-1a

# 3. Save the SUBNETS ID to an environment variable
PUBLIC_SUBNET_ID=YOUR_PUBLIC_SUBNET_ID
PRIVATE_SUBNET_ID=YOUR_PRIVATE_SUBNET_ID

By default, instances launched in a VPC do not get public IP addresses. We’ll modify the public subnet so that any server placed inside it automatically receives a public IP.

# Update the public subnet to automatically map a public IP on launch
aws ec2 modify-subnet-attribute \
  --subnet-id $PUBLIC_SUBNET_ID \
  --map-public-ip-on-launch

Step 3: Create and Attach the Internet Gateway Link to heading

Our VPC needs a door to the internet. We’ll create the Internet Gateway first, and then attach it to our VPC.

# 1. Create the gateway resource
aws ec2 create-internet-gateway

# 2. Store the gateway id in an environment variable
IGW_ID=YOUR_IGW_ID

# 3. Attach the newly created gateway to your VPC
aws ec2 attach-internet-gateway \
  --vpc-id $VPC_ID \
  --internet-gateway-id $IGW_ID

Step 4: Configure the Route Table Link to heading

Right now, our “public” subnet doesn’t know the internet gateway exists. We need to create a custom route table, add a rule to send internet-bound traffic to the gateway, and link this table exclusively to our public subnet.

# 1. Create a new, custom route table for the VPC
aws ec2 create-route-table \
  --vpc-id $VPC_ID

# 2. Store the route table id to an environment table
ROUTE_TABLE_ID=YOUR_ROUTE_TABLE_ID

# 3. Add a route pointing all outside traffic (0.0.0.0/0) to the Internet Gateway
aws ec2 create-route \
  --route-table-id $ROUTE_TABLE_ID \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id $IGW_ID

# 4. Associate this new route table explicitly with the Public Subnet
aws ec2 associate-route-table \
  --subnet-id $PUBLIC_SUBNET_ID \
  --route-table-id $ROUTE_TABLE_ID

(We leave the private subnet alone. It will rely on the VPC’s hidden default route table, which only permits local internal traffic).

Step 5: Create a Key Pair for SSH Access Link to heading

To log into our servers later, we need a cryptographic key pair. This command creates the key in AWS and saves the private key locally as a .pem file on your computer.

# Create the key pair and output the private key material to a local file
aws ec2 create-key-pair \
  --key-name MyAWSKey \
  --query 'KeyMaterial' \
  --output text > MyAWSKey.pem

# Note: If you are on Mac or Linux, you must secure the file permissions
# so SSH allows you to use it. Run this command:
chmod 400 MyAWSKey.pem

Step 6: Security Groups Link to heading

We need a virtual firewall (Security Group) for our servers. First, we create the group, then we add two rules: one allowing SSH access so we can log in, and one allowing ICMP (Ping) traffic from inside the VPC so our servers can talk to each other.

# 1. Create the Security Group
aws ec2 create-security-group \
  --group-name MySecurityGroup \
  --description "Allow SSH and Ping" \
  --vpc-id $VPC_ID

# 2. Store the Security Group ID in an environment variable
SG_ID=YOUR_SG_ID

# 3. Allow inbound SSH (Port 22) from anywhere (0.0.0.0/0)
aws ec2 authorize-security-group-ingress \
  --group-id $SG_ID \
  --protocol tcp \
  --port 22 \
  --cidr 0.0.0.0/0

# 4. Allow inbound ICMP (Ping) traffic only from within the VPC network (10.0.0.0/16)
aws ec2 authorize-security-group-ingress \
  --group-id $SG_ID \
  --protocol icmp \
  --port -1 \
  --cidr 10.0.0.0/16

Step 7: Launch EC2 Instances Link to heading

Now, let’s deploy a server into each subnet! (Note: You will need an Amazon Linux AMI ID for your specific region. You can easily find the free tier Amazon Linux 2023 AMI ID in the AWS Console on EC2 > AMI Catalog).

First, we deploy our internet-facing Amazon Linux 2023 (ami-06067086cf86c58e6 for my account, yours may vary) web server into the public subnet, attaching the key pair and security group we just created.

# Launch the Web Server into the PUBLIC subnet
aws ec2 run-instances \
  --image-id YOUR_AMI_ID \
  --count 1 \
  --instance-type t2.micro \
  --key-name MyAWSKey \
  --security-group-ids $SG_ID \
  --subnet-id $PUBLIC_SUBNET_ID

# Store the instance ID
PUBLIC_INSTANCE_ID=YOUR_PUBLIC_INSTANCE_ID

# Get the public IP address of the web server
aws ec2 describe-instances \
  --instance-ids $PUBLIC_INSTANCE_ID \
  --query 'Reservations[0].Instances[0].PublicIpAddress' \
  --output text

Next, we deploy our backend database server into the isolated private subnet.

# Launch the Database Server into the PRIVATE subnet
aws ec2 run-instances \
  --image-id YOUR_AMI_ID \
  --count 1 \
  --instance-type t2.micro \
  --key-name MyAWSKey \
  --security-group-ids $SG_ID \
  --subnet-id $PRIVATE_SUBNET_ID

PRIVATE_INSTANCE_ID=YOUR_PRIVATE_INSTANCE_ID

# Get the private IP address of the web server
aws ec2 describe-instances \
  --instance-ids $PRIVATE_INSTANCE_ID \
  --query 'Reservations[0].Instances[0].PrivateIpAddress' \
  --output text

Step 8: The “Ping” Test Link to heading

It’s time for the “Aha!” moment.

  1. Open your terminal, locate your MyAWSKey.pem file, and use SSH to log into your Public Web Server using its public IP address:

    ssh -i MyAWSKey.pem ec2-user@YOUR_PUBLIC_IP
    
  2. Once securely inside the public server, ping the private IP address of your Database Server (e.g., ping 10.0.2.x).

Success! The ping works because both servers live inside the same VPC and can talk to each other locally. However, if you try to ping the private server directly from your laptop at home, it will fail. It has no public IP and no route to the outside world. It is completely safe!

Cancel the ping command with Ctrl+C and then logout the server with Ctrl+D (or the equivalent on Mac).

Moving to Production: What We Left Out Link to heading

The lab we just built is a fantastic learning tool, but it is not ready for a real-world, production application. If you were deploying a real app for a company, you would need to add a few critical things:

  • High Availability (Multi-AZ): We placed all our servers in a single Availability Zone (us-east-1a). If that physical data center has a power outage, our app goes down. In production, you always spread your subnets and servers across at least two different AZs.
  • Strict Security: In Step 6, we opened SSH (Port 22) to the entire world (0.0.0.0/0). Never do this in production! You should restrict access to your company’s specific IP address, or better yet, use AWS Systems Manager (SSM) which allows secure remote access without opening any inbound ports at all.
  • NAT Gateways: Our private database server is completely cut off from the internet. If it needs to download a vital Linux security patch, it can’t. Production environments use NAT Gateways to allow private instances to reach out to the internet for updates while keeping them hidden from incoming internet traffic.
  • Application Load Balancers (ALB): Instead of users connecting directly to a single web server’s public IP address, production apps use Load Balancers. The Load Balancer sits in the public subnet, accepts incoming traffic, and evenly distributes it to dozens of private web servers hidden safely behind it.

Clean Up: Deleting Your Resources Link to heading

In the cloud, you pay for what you provision. Leaving things running when you are done learning is a quick way to get a surprise bill.

You can’t just delete a VPC; you have to delete the things inside it first to avoid dependency errors. Run these commands in this exact order to safely tear down your lab:

1. Terminate the EC2 Instances: This stops and deletes your virtual servers.

aws ec2 terminate-instances --instance-ids $PUBLIC_INSTANCE_ID $PRIVATE_INSTANCE_ID

(Wait a few minutes for them to fully shut down before proceeding).

2. Delete Security Group: Removes your virtual firewall rules.

aws ec2 delete-security-group --group-id $SG_ID

3. Delete Subnets: Removes your public and private network boundaries.

# Delete both the public and private subnet IDs
aws ec2 delete-subnet --subnet-id $PUBLIC_SUBNET_ID
aws ec2 delete-subnet --subnet-id $PRIVATE_SUBNET_ID

4. Detach Internet Gateway: Unplugs the gateway from your VPC.

aws ec2 detach-internet-gateway \
  --internet-gateway-id $IGW_ID \
  --vpc-id $VPC_ID

5. Delete Internet Gateway: Destroys the gateway resource.

aws ec2 delete-internet-gateway --internet-gateway-id $IGW_ID

6. Delete Route Table: Removes your custom routing rules.

aws ec2 delete-route-table --route-table-id $ROUTE_TABLE_ID

7. Delete the VPC: Delete the empty virtual private cloud itself.

aws ec2 delete-vpc --vpc-id $VPC_ID

8. Delete the Key Pair: Finally, remove the public key from AWS and delete your local file.

aws ec2 delete-key-pair --key-name MyAWSKey
rm MyAWSKey.pem

Conclusion Link to heading

Congratulations! You just went from learning about massive physical data centers down to creating your very own logically isolated network in the cloud. You learned how to route public traffic, secure private traffic, and verify access using SSH keys.

Now that you have the basics down, you’re well on your way to mastering cloud architecture!

Interested on launching your app to production on AWS? Let’s talk