Amazon Elastic Compute Cloud (EC2) provides resizable virtual servers in the cloud. EC2 is the workhorse of AWS — web servers, batch jobs, bastion hosts, and container nodes all run on EC2 unless you choose a fully managed alternative.

How EC2 Works

When you launch an instance, AWS provisions a VM on shared hardware in your chosen AZ. You select an AMI (Amazon Machine Image), instance type, storage, and networking. You pay per second (Linux/Windows) for running instances.

  Launch Request → AMI + Instance Type + Subnet + SG → Running Instance
                                                      ↓
                                              EBS Volume (persistent)
  

Launch an Instance (CLI)

  # Find a current Amazon Linux 2023 AMI
aws ec2 describe-images \
    --owners amazon \
    --filters "Name=name,Values=al2023-ami-2023*" "Name=architecture,Values=x86_64" \
    --query 'Images | sort_by(@, &CreationDate) | [-1].ImageId' \
    --output text

# Launch instance
aws ec2 run-instances \
    --image-id ami-0c55b159cbfafe1f0 \
    --instance-type t3.micro \
    --key-name my-key \
    --security-group-ids sg-0123456789abcdef0 \
    --subnet-id subnet-0123456789abcdef0 \
    --iam-instance-profile Name=EC2-S3-Profile \
    --metadata-options "HttpTokens=required" \
    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=web-server},{Key=Environment,Value=dev}]' \
    --count 1
  

Console path: EC2 → Launch Instance → Amazon Linux 2023 → t3.micro → Create key pair → Select VPC/subnet → Configure security group → Launch.

Connect via SSH

  chmod 400 my-key.pem
ssh -i my-key.pem ec2-user@<public-ip>

# Amazon Linux 2023 default user: ec2-user
# Ubuntu AMI default user: ubuntu
# Debian AMI default user: admin
  

Session Manager (No SSH Key Required)

  # Requires SSM agent + IAM role with AmazonSSMManagedInstanceCore
aws ssm start-session --target i-0123456789abcdef0
  

Prefer Session Manager in production — no open port 22, full audit trail in CloudTrail.

Instance Types

Family vCPU/RAM Profile Use Case Example
t3/t4g Burstable Dev/test, low-traffic web t3.micro (Free Tier)
m7i/m7g Balanced General web apps, APIs m7i.large
c7i/c7g Compute-heavy Batch, transcode, gaming c7i.xlarge
r7i/r7g Memory-heavy Caches, in-memory DBs r7i.2xlarge
g5/p4 GPU ML training/inference g5.xlarge

Use the AWS Instance Type Explorer to compare. Graviton (t4g, m7g) instances offer 20–40% better price-performance for compatible workloads.

Storage Options

Type Persistence Performance Use Case
EBS gp3 Persistent Configurable IOPS/throughput Boot volumes, databases
EBS io2 Persistent Highest IOPS Mission-critical DBs
Instance Store Ephemeral NVMe, very fast Temp caches, scratch
EFS Shared, persistent NFS protocol Multi-instance shared files
  # Create and attach an additional EBS volume
aws ec2 create-volume --size 100 --volume-type gp3 --availability-zone us-east-1a
aws ec2 attach-volume --volume-id vol-xxx --instance-id i-xxx --device /dev/sdf

# On the instance:
sudo mkfs -t xfs /dev/xvdf
sudo mkdir /data && sudo mount /dev/xvdf /data
  

Security Groups

Stateful firewalls attached to instances:

  # Allow HTTP and HTTPS from anywhere
aws ec2 authorize-security-group-ingress \
    --group-id sg-xxx \
    --protocol tcp --port 80 --cidr 0.0.0.0/0

aws ec2 authorize-security-group-ingress \
    --group-id sg-xxx \
    --protocol tcp --port 443 --cidr 0.0.0.0/0

# Allow SSH only from your office IP
aws ec2 authorize-security-group-ingress \
    --group-id sg-xxx \
    --protocol tcp --port 22 --cidr 203.0.113.50/32
  

Best practice: Application servers in private subnets; load balancer in public subnets. No direct SSH from 0.0.0.0/0.

Auto Scaling Groups

Automatically maintain desired capacity and replace unhealthy instances:

  # 1. Create launch template
aws ec2 create-launch-template \
    --launch-template-name web-lt \
    --launch-template-data '{
        "ImageId": "ami-0c55b159cbfafe1f0",
        "InstanceType": "t3.small",
        "SecurityGroupIds": ["sg-xxx"],
        "IamInstanceProfile": {"Name": "EC2-AppRole"}
    }'

# 2. Create Auto Scaling Group
aws autoscaling create-auto-scaling-group \
    --auto-scaling-group-name web-asg \
    --launch-template LaunchTemplateName=web-lt,Version=1 \
    --min-size 2 --max-size 10 --desired-capacity 2 \
    --vpc-zone-identifier "subnet-aaa,subnet-bbb" \
    --target-group-arns arn:aws:elasticloadbalancing:us-east-1:123:targetgroup/web/xxx \
    --health-check-type ELB

# 3. Scale on CPU
aws autoscaling put-scaling-policy \
    --auto-scaling-group-name web-asg \
    --policy-name scale-on-cpu \
    --policy-type TargetTrackingScaling \
    --target-tracking-configuration '{
        "PredefinedMetricSpecification": {
            "PredefinedMetricType": "ASGAverageCPUUtilization"
        },
        "TargetValue": 60.0
    }'
  

User Data (Bootstrap Scripts)

Run commands on first boot:

  aws ec2 run-instances \
    --image-id ami-xxx \
    --instance-type t3.micro \
    --user-data file://bootstrap.sh \
    ...
  
  #!/bin/bash
# bootstrap.sh
yum update -y
yum install -y docker
systemctl start docker
systemctl enable docker
docker run -d -p 80:80 nginx:latest
  

Real-World Scenario: Three-Tier Web App

Tier EC2 Config Notes
Web (ASG) 2× t3.small across 2 AZs Behind ALB, private subnets
App (ASG) 2× m7i.large No public IP, SG allows ALB only
Bastion 1× t3.micro Public subnet, SSH restricted to VPN IP

Database runs on RDS (not EC2) for managed backups and patching.

EC2 vs Alternatives

Option When to Choose
EC2 Full OS control, legacy apps, custom networking
Lambda Event-driven, short-lived, no server management
ECS/Fargate Containerized apps without managing EC2
Elastic Beanstalk Quick deploy of web apps with minimal config

Common Mistakes

  1. Running production on t3.micro — burstable credits exhaust under sustained load
  2. No Auto Scaling — manual capacity management doesn’t survive traffic spikes
  3. Public instances with default SG — exposes all ports internally
  4. Forgetting EBS snapshots — instance store data is lost on stop/terminate
  5. IMDSv1 enabled — use IMDSv2 (HttpTokens=required) to prevent SSRF credential theft

Troubleshooting

Issue Check Fix
Cannot SSH SG, NACL, key pair, public IP Verify port 22 allowed from your IP
Instance status checks failed OS crash, full disk Reboot; check /var/log/messages via SSM
High CPU, throttled t3 burst credits exhausted Upgrade to m-family or enable unlimited mode
Cannot reach internet No NAT Gateway in private subnet Add NAT GW or use public subnet with EIP

Best Practices

  • Use launch templates (not launch configurations)
  • Deploy across multiple AZs for high availability
  • Attach IAM roles instead of embedding access keys
  • Enable detailed monitoring for production ASGs
  • Use gp3 EBS — cheaper and more configurable than gp2
  • Stop (not terminate) dev instances overnight to save costs
  • Patch AMIs regularly with EC2 Image Builder

Next: S3 — Object Storage.