AWS EC2 Cloud Auto Scaling

AWS EC2 Complete Guide: Launch, Secure & Auto-Scale

AF
Amelia Foster
Cloud Architect @ AWS
Jun 20, 2025
24 min read

What You'll Learn

A hands-on guide to launching, connecting, and managing AWS EC2 instances — covering instance types, security groups, key pairs, user data scripts, AMIs, and Auto Scaling.

What is EC2?

Amazon EC2 (Elastic Compute Cloud) provides resizable virtual servers — called instances — in the cloud. You can launch Linux or Windows instances in minutes, choose from hundreds of instance types, and pay only for what you use.

t3.micro
2 vCPU / 1GB RAM
Free Tier
m6i.2xl
8 vCPU / 32GB RAM
General Purpose
c6g.xlarge
4 vCPU / 8GB RAM
Compute Optimized
r7g.4xl
16 vCPU / 128GB RAM
Memory Optimized

Launching EC2 via AWS CLI

AWS CLI — Launch EC2 Instance
# 1. Configure AWS CLI
aws configure
# AWS Access Key ID: AKIAIOSFODNN7EXAMPLE
# AWS Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# Default region: us-east-1

# 2. Launch an EC2 instance
aws ec2 run-instances \
    --image-id ami-0c02fb55956c7d316 \    # Amazon Linux 2023
    --instance-type t3.micro \
    --key-name my-keypair \
    --security-group-ids sg-0123456789abcdef0 \
    --subnet-id subnet-0123456789abcdef0 \
    --iam-instance-profile Name=EC2-S3-Role \
    --user-data file://userdata.sh \
    --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=my-webserver},{Key=Env,Value=prod}]' \
    --count 1

# 3. Check instance status
aws ec2 describe-instances \
    --filters "Name=tag:Name,Values=my-webserver" \
    --query 'Reservations[*].Instances[*].[InstanceId,State.Name,PublicIpAddress]' \
    --output table

# 4. Stop / Start / Terminate
aws ec2 stop-instances --instance-ids i-1234567890abcdef0
aws ec2 start-instances --instance-ids i-1234567890abcdef0
aws ec2 terminate-instances --instance-ids i-1234567890abcdef0

User Data Script — Bootstrap Your Instance

User data is a script that runs automatically when an instance first starts. Use it to install software, configure the system, and start services.

userdata.sh — Install Nginx + Node.js
#!/bin/bash
set -e  # Exit on error

# Update system packages
yum update -y

# Install Nginx
yum install -y nginx
systemctl enable nginx
systemctl start nginx

# Install Node.js 20 via NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
export NVM_DIR="/root/.nvm"
source "$NVM_DIR/nvm.sh"
nvm install 20
nvm use 20

# Install Docker
yum install -y docker
systemctl enable docker
systemctl start docker
usermod -aG docker ec2-user

# Pull and run the application
docker pull my-registry/myapp:latest
docker run -d \
    --name myapp \
    --restart unless-stopped \
    -p 3000:3000 \
    -e NODE_ENV=production \
    my-registry/myapp:latest

# Configure Nginx as reverse proxy
cat > /etc/nginx/conf.d/myapp.conf << 'EOF'
server {
    listen 80;
    server_name _;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
EOF

systemctl reload nginx

# Signal success
/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource MyInstance --region ${AWS::Region}

echo "Bootstrap complete!" >> /var/log/userdata.log

Security Groups — Instance Firewall

AWS CLI — Configure Security Group
# Create security group
aws ec2 create-security-group \
    --group-name web-servers-sg \
    --description "Security group for web servers" \
    --vpc-id vpc-0123456789abcdef0

# Add inbound rules
aws ec2 authorize-security-group-ingress \
    --group-id sg-0123456789abcdef0 \
    --ip-permissions \
        'IpProtocol=tcp,FromPort=80,ToPort=80,IpRanges=[{CidrIp=0.0.0.0/0,Description="HTTP from internet"}]' \
        'IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges=[{CidrIp=0.0.0.0/0,Description="HTTPS from internet"}]' \
        'IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges=[{CidrIp=10.0.0.0/8,Description="SSH from VPN only"}]'

# Best Practice: Restrict SSH to your IP ONLY, never 0.0.0.0/0!

Auto Scaling Group + Launch Template

Auto Scaling Setup
# 1. Create Launch Template
aws ec2 create-launch-template \
    --launch-template-name MyAppTemplate \
    --version-description "v1" \
    --launch-template-data '{
        "ImageId": "ami-0c02fb55956c7d316",
        "InstanceType": "t3.micro",
        "KeyName": "my-keypair",
        "SecurityGroupIds": ["sg-0123456789abcdef0"],
        "UserData": "'"$(base64 -w 0 userdata.sh)"'",
        "IamInstanceProfile": {"Name": "EC2-Role"},
        "Monitoring": {"Enabled": true}
    }'

# 2. Create Auto Scaling Group
aws autoscaling create-auto-scaling-group \
    --auto-scaling-group-name MyAppASG \
    --launch-template LaunchTemplateName=MyAppTemplate,Version='$Latest' \
    --min-size 2 \
    --max-size 10 \
    --desired-capacity 3 \
    --availability-zones us-east-1a us-east-1b us-east-1c \
    --target-group-arns arn:aws:elasticloadbalancing:...

# 3. Create scaling policy (scale up when CPU > 70%)
aws autoscaling put-scaling-policy \
    --policy-name scale-up \
    --auto-scaling-group-name MyAppASG \
    --policy-type TargetTrackingScaling \
    --target-tracking-configuration '{
        "TargetValue": 70.0,
        "PredefinedMetricSpecification": {
            "PredefinedMetricType": "ASGAverageCPUUtilization"
        }
    }'

Cost Optimization Tips

  • Spot Instances — Up to 90% cheaper. Use for non-critical, fault-tolerant workloads.
  • Reserved Instances — 40-60% savings for predictable workloads (1 or 3 year commitment).
  • Savings Plans — Flexible alternative to RIs — commit to $/hour, apply across instance types.
  • Right-sizing — Use AWS Compute Optimizer to find oversized instances.
  • Stop dev instances — Schedule non-production instances to stop at night with AWS Instance Scheduler.
  • S3 for static assets — Don't serve static files from EC2; use S3 + CloudFront instead.

Keep Reading

D
DevOps

Docker Networking Demystified: Bridge, Host & Overlay

8 min read Read More
C
Cloud

AWS IAM Roles vs Users vs Policies

10 min read Read More
P
Programming

Understanding Python's GIL & Multiprocessing

14 min read Read More