EC2 gives you virtual servers on demand. A first instance teaches the five pieces you will meet in every deployment: the AMI (the image), the instance type (the size), the key pair (how you log in), the security group (the firewall) and the EBS volume (the disk).
State of AWS on this date. Amazon Linux 2 is the current Amazon Linux release, supported until 2023. t2.micro (1 vCPU, 1 GiB RAM) is Free Tier eligible for the first 12 months, up to 750 hours a month. The default root volume type is gp2 (the newer gp3 volumes do not exist yet). Instance Metadata Service version 2 (IMDSv2) was introduced in November 2019 and should be required for new instances.
What you create
flowchart TB
ME[Your laptop] -->|SSH 22 from your IP only| SG[Security group<br/>stateful firewall]
SG --> EC2[EC2 instance t2.micro<br/>Amazon Linux 2]
EC2 --> EBS[(EBS root volume 8 GiB gp2)]
EC2 --> ENI[Network interface<br/>in default VPC subnet]
ENI --> EIP[Public IPv4 address<br/>changes on stop and start]
AMI[AMI Amazon Linux 2] -.->|boots from| EC2
KP[Key pair public key on instance] -.-> EC2
ROLE[IAM instance profile<br/>optional] -.-> EC2
Launch with the CLI
export AWS_REGION=ap-south-1
# 1. Key pair (private key shown once)
aws ec2 create-key-pair --key-name lab-key --query 'KeyMaterial' --output text > lab-key.pem
chmod 400 lab-key.pem
# 2. Security group allowing SSH from your IP only
MYIP=$(curl -s https://checkip.amazonaws.com)
SG=$(aws ec2 create-security-group --group-name lab-ssh --description "SSH from my IP" --query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id $SG --protocol tcp --port 22 --cidr ${MYIP}/32
# 3. Latest Amazon Linux 2 AMI via the public SSM parameter
AMI=$(aws ssm get-parameters --names /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 \
--query 'Parameters[0].Value' --output text)
# 4. Launch with IMDSv2 required and tags
aws ec2 run-instances --image-id $AMI --instance-type t2.micro --key-name lab-key \
--security-group-ids $SG --count 1 \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=lab-1},{Key=owner,Value=ravi}]'
# 5. Wait and connect
IID=$(aws ec2 describe-instances --filters Name=tag:Name,Values=lab-1 Name=instance-state-name,Values=running,pending --query 'Reservations[0].Instances[0].InstanceId' --output text)
aws ec2 wait instance-running --instance-ids $IID
IP=$(aws ec2 describe-instances --instance-ids $IID --query 'Reservations[0].Instances[0].PublicIpAddress' --output text)
ssh -i lab-key.pem ec2-user@$IP
The default user on Amazon Linux 2 is ec2-user (ubuntu on Ubuntu AMIs). The console wizard does the same steps; the CLI version is repeatable and reviewable.
First things to do on the instance
sudo yum update -y
cat /etc/os-release | head -3
df -h /; free -m
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 60")
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id
The metadata service at 169.254.169.254 exposes instance details and role credentials. Requiring IMDSv2 (a session token) blocks a class of attacks where a vulnerable web application is tricked into fetching credentials.
Security basics
- Security group: allow only the ports you serve; SSH only from your address or a bastion. Security groups are stateful, deny by default, and allow-only (no deny rules).
- Keys: one key per person is better; protect
.pemfiles and rotate. Never bake keys into AMIs. - No credentials on the instance: attach an IAM instance profile with least privilege rather than running
aws configure. - Patch: Amazon Linux 2 receives security updates through
yum; enable automatic checks or use Systems Manager Patch Manager. - EC2 Instance Connect or Session Manager let you log in without opening port 22 at all; worth adopting soon.
Costs and lifecycle
| State | Compute billed? | EBS billed? | Public IP |
|---|---|---|---|
| running | yes | yes | kept |
| stopped | no | yes | released (use an Elastic IP to keep one) |
| terminated | no | root deleted by default | released |
An Elastic IP that is not attached to a running instance is charged, so release it when finished. Check aws ec2 describe-instances and describe-volumes for forgotten resources.
Clean up
aws ec2 terminate-instances --instance-ids $IID
aws ec2 wait instance-terminated --instance-ids $IID
aws ec2 delete-security-group --group-id $SG
aws ec2 delete-key-pair --key-name lab-key && rm lab-key.pem
Add a budget alert (see the account-setup post) before you leave anything running overnight.