EC2: your first server in the cloud
Launch a real server in the console step by step: pick an AMI and instance type, a key pair and a firewall, bootstrap it with user data, SSH in, then terminate it so it stops costing money.
By the end of this lesson you'll be able to
0 of 5 completeWhat you're building
One small Linux server in Mumbai (ap-south-1) that serves a web page, reachable by SSH only from your own IP.
Everything below was done in a real practice account, screen by screen, and deleted afterwards. The red
numbered boxes show what to click or fill in.
Open EC2 → Instances → Launch instances. It's one long page; work down it.
Name and AMI
An AMI (Amazon Machine Image) is the disk the server boots from: an operating system plus anything already
installed. Amazon Linux 2023 is AWS's own distribution, tuned for EC2 and using dnf. Ubuntu and Debian work
the same way; their default user is ubuntu or admin instead of ec2-user. Teams often build their own AMI
with the app preinstalled so new servers start in seconds.
Instance type
The name says what you get: t3.micro is family t, generation 3, size micro.
| Family | For | Example |
|---|---|---|
| t (burstable) | small or spiky workloads: dev servers, small sites | t3.micro, t4g.small |
| m (general purpose) | balanced apps and APIs | m7i.large |
| c (compute) | CPU-heavy work: builds, encoding | c7i.xlarge |
| r (memory) | databases, caches | r7i.large |
| i, d (storage) | fast local disks | i4i.large |
Burstable t-types earn CPU credits while idle and spend them in bursts. A t-instance busy all day runs out
and either slows down or, in the default unlimited mode, costs extra. A g in the name (t4g, m7g) means
Graviton, AWS's Arm processor: usually cheaper for the same work, if your software has an Arm build.
Key pair
A key pair is an SSH key: AWS puts the public key on the server and you keep the private .pem file.
Create new key pair downloads it exactly once; lose it and you can't log in with it again. From the CLI:
$ aws ec2 create-key-pair --key-name academy-key --key-type ed25519 \ --query KeyMaterial --output text > academy-key.pem $ chmod 400 academy-key.pem
aws ec2 create-key-pair --key-name academy-key --key-type ed25519 \awsthe AWS command line
chmod 400 academy-key.pemchmodchange permissions
Firewall: the security group
A security group is a firewall around the instance. It's stateful: allow a request in and its reply is allowed out automatically. By default nothing comes in and everything goes out. The wizard writes these rules for you:
| Port | Source | Why |
|---|---|---|
| 22 (SSH) | your IP /32 | only you can even try to log in |
| 80 (HTTP) | 0.0.0.0/0 | the web page is public |
Storage and user data
The root disk is an EBS volume: network storage that survives a stop and start, and is deleted on terminate by default. Some types also have an instance store: fast local disks that are wiped when the instance stops. Never keep data there that you can't lose. Lesson 7 covers storage in depth.
Under Advanced details, the last field is User data: a script that runs once, as root, on first boot:
#!/bin/bash dnf install -y nginx echo "<h1>Hello from $(hostname)</h1>" > /usr/share/nginx/html/index.html systemctl enable --now nginx
Its output goes to /var/log/cloud-init-output.log on the instance: look there first when a server comes up
without your software.
Launch
What you just made
The instance has a private IP inside the VPC (lesson 4) and a public IP from AWS's pool. The public IP changes every time the instance stops and starts. An Elastic IP is a public address you keep, but AWS charges for every public IPv4 address, so release the ones you don't use.
Connect
Session Manager (part of AWS Systems Manager) opens a shell through the SSM agent and IAM, with no port 22,
no key and every session logged. It needs the instance to have a role with AmazonSSMManagedInstanceCore
(lesson 2's instance profile). For production it's the better default.
Inside the server
169.254.169.254 is the instance metadata service: the instance asks it who it is, what type it is, and
for its role's temporary credentials. With IMDSv2 (required on this instance, as the details page showed)
every request needs a token from a PUT first, so a request without one gets HTTP 401. That stops attacks
that trick an app into fetching a URL and leaking the credentials.
What it costs
The instance type page showed the price: about $0.0112 an hour for a Linux t3.micro in Mumbai, around $8 a month if left on. Free tier offers depend on when your account was created; check Billing → Free Tier before relying on them.
| Option | Pay | Good for |
|---|---|---|
| On-Demand | per second, no commitment | testing, unpredictable load |
| Spot | up to 90% less, but AWS can take it back with a 2-minute warning | batch jobs, CI runners, anything that can restart |
| Savings Plans | lower rate for committing to $/hour for 1 or 3 years | steady production load |
| Reserved Instances | discount for committing to one instance type | older alternative to Savings Plans |
Clean up
Instance state → Terminate (delete) instance:
A terminated instance leaves its security group and key pair behind; delete those too:
$ aws ec2 terminate-instances --instance-ids i-0fc778d720d76ed3c $ aws ec2 wait instance-terminated --instance-ids i-0fc778d720d76ed3c $ aws ec2 delete-security-group --group-id sg-01ff1639efcb487b9 $ aws ec2 delete-key-pair --key-name academy-key
aws ec2 terminate-instances --instance-ids i-0fc778d720d76ed3cawsthe AWS command line
A web server from one command
Launch the same server from the CLI: a key pair, a security group with SSH from your IP and HTTP from anywhere, and a t3.micro running Amazon Linux 2023 with the nginx user data. Prove the page answers and that IMDSv2 rejects a request without a token, then delete everything.
curl showing Hello from the instance, HTTP 401 without a metadata token, then no instance, security group or key pair leftReveal one safe solution
$ MYIP=$(curl -s https://checkip.amazonaws.com) $ AMI=$(aws ssm get-parameter --name /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 --query Parameter.Value --output text) $ aws ec2 create-key-pair --key-name academy-key --key-type ed25519 --query KeyMaterial --output text > academy-key.pem && chmod 400 academy-key.pem $ SG=$(aws ec2 create-security-group --group-name academy-web --description "SSH from me, HTTP from all" --query GroupId --output text) $ aws ec2 authorize-security-group-ingress --group-id $SG --protocol tcp --port 22 --cidr $MYIP/32 $ aws ec2 authorize-security-group-ingress --group-id $SG --protocol tcp --port 80 --cidr 0.0.0.0/0 $ printf '#!/bin/bash\ndnf install -y nginx\necho "<h1>Hello from $(hostname)</h1>" > /usr/share/nginx/html/index.html\nsystemctl enable --now nginx\n' > user-data.sh $ ID=$(aws ec2 run-instances --image-id $AMI --instance-type t3.micro --key-name academy-key --security-group-ids $SG \ --user-data file://user-data.sh --metadata-options HttpTokens=required \ --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=academy-web}]' --query 'Instances[0].InstanceId' --output text) $ aws ec2 wait instance-status-ok --instance-ids $ID $ IP=$(aws ec2 describe-instances --instance-ids $ID --query 'Reservations[0].Instances[0].PublicIpAddress' --output text) $ curl -s http://$IP $ ssh -o StrictHostKeyChecking=accept-new -i academy-key.pem ec2-user@$IP 'curl -s -o /dev/null -w "%{http_code}\n" http://169.254.169.254/latest/meta-data/instance-type' 401 $ aws ec2 terminate-instances --instance-ids $ID && aws ec2 wait instance-terminated --instance-ids $ID $ aws ec2 delete-security-group --group-id $SG && aws ec2 delete-key-pair --key-name academy-key && rm academy-key.pem
aws ec2 create-key-pair --key-name academy-key --key-type ed25519 --query KeyMaterial --output text > academy-key.pem && chmod 400 academy-key.pemawsthe AWS command line--querypick fields from the JSON response--outputoutput format>write output to a file, replacing it&&run the next command only if this one workedchmodchange permissions
curl -s http://$IPcurlmake an HTTP request-ssilent: no progress bar
ssh -o StrictHostKeyChecking=accept-new -i academy-key.pem ec2-user@$IP 'curl -s -o /dev/null -w "%{http_code}\n" http://169.254.169.254/latest/meta-data/instance-type'sshlog in to another machine securely
aws ec2 delete-security-group --group-id $SG && aws ec2 delete-key-pair --key-name academy-key && rm academy-key.pemrmdelete files, with no undo
instance-status-ok waits until both status checks pass, which can take a few minutes. The whole mission costs
a cent or two at On-Demand prices, nothing within the free tier.
Try it yourself
0 of 6 steps doneRun each task in your own account or terminal, then tick it off.
Quick check
What is an AMI?
Official reading for this lesson
Or get every quiz answer right and it completes itself.