Amazon Web Services is the most widely used cloud platform. This guide walks you through setting up your first production-ready infrastructure with EC2 instances inside a properly configured VPC.
What Is a VPC?
A Virtual Private Cloud (VPC) is your own isolated network within AWS. You control the IP address range, subnets, route tables, and security rules.
Creating a VPC
# Using AWS CLI
aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=my-vpc}]'
Or in Terraform:
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "my-vpc"
}
}
Subnets
Divide your VPC into public and private subnets across availability zones:
| Subnet | CIDR | Type | AZ |
|---|---|---|---|
| Public A | 10.0.1.0/24 | Public | us-east-1a |
| Public B | 10.0.2.0/24 | Public | us-east-1b |
| Private A | 10.0.10.0/24 | Private | us-east-1a |
| Private B | 10.0.20.0/24 | Private | us-east-1b |
Public subnets have a route to an Internet Gateway. Private subnets use a NAT Gateway for outbound internet access.
resource "aws_subnet" "public_a" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-1a"
map_public_ip_on_launch = true
tags = { Name = "public-a" }
}
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.main.id
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gw.id
}
}
Security Groups
Security groups act as virtual firewalls for your instances:
resource "aws_security_group" "web" {
name = "web-sg"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["YOUR_IP/32"] # Restrict SSH to your IP
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Key rules: allow HTTP/HTTPS from anywhere, restrict SSH to your IP only.
Launching an EC2 Instance
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0" # Amazon Linux 2023
instance_type = "t3.micro"
subnet_id = aws_subnet.public_a.id
vpc_security_group_ids = [aws_security_group.web.id]
key_name = aws_key_pair.deployer.key_name
root_block_device {
volume_size = 20
volume_type = "gp3"
encrypted = true
}
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y docker
systemctl start docker
systemctl enable docker
usermod -aG docker ec2-user
EOF
tags = { Name = "web-server" }
}
Key Pairs
Create a key pair for SSH access:
# Generate locally
ssh-keygen -t ed25519 -f ~/.ssh/aws-key -C "deploy@myorg"
# Import to AWS
aws ec2 import-key-pair --key-name deployer --public-key-material fileb://~/.ssh/aws-key.pub
Connect:
ssh -i ~/.ssh/aws-key ec2-user@<public-ip>
Elastic IPs
Assign a static public IP so it survives instance restarts:
aws ec2 allocate-address --domain vpc
aws ec2 associate-address --instance-id i-1234567890 --allocation-id eipalloc-abc123
Best Practices
- Place application servers in private subnets behind a load balancer
- Use IAM roles instead of access keys on EC2 instances
- Enable VPC Flow Logs for network monitoring
- Use multiple availability zones for high availability
- Encrypt all EBS volumes
- Tag every resource for cost tracking
- Use Systems Manager Session Manager instead of direct SSH when possible
Cost Tips
- Use Spot Instances for non-critical workloads (up to 90% savings)
- Right-size instances based on CloudWatch metrics
- Use Reserved Instances or Savings Plans for predictable workloads
- Set up billing alerts in AWS Budgets
AWS infrastructure starts with a solid VPC foundation. Get the networking right, and everything else — EC2, RDS, ECS, Lambda — builds on top of it.
Tagged with
Enjoyed this article?
Get more DevOps insights delivered to your inbox.
Get new posts by email
Subscribe to get an email when a new blog post is published. Skip anytime.
No spam, unsubscribe anytime.
Related Posts
Discussion
0 comments
Sign in to join the conversation.
Be the first to comment
Start a conversation about this post
