AWS basics · Lesson 4 · 40 min

EC2: launch a Linux server

EC2 (Elastic Compute Cloud) rents you virtual machines: a real Linux server with CPUs, memory and a disk, ready in about a minute. You pick an image, a size, a network and a key, and you can hand it a script to run on first boot. After that it's a Linux box like any other, and everything from the Linux paths works on it.

You will learn

  • AMIs, instance types, key pairs and EBS disks
  • Finding the latest Amazon Linux or Ubuntu image with SSM parameters
  • User data: a script cloud-init runs as root on first boot
  • run-instances, wait, describe-instances, then curl and ssh -i
  • Stop, start and terminate, and what each one costs

The ingredients

IngredientWhat it isExample
AMIAmazon Machine Image: the disk the server starts from (OS + anything pre-installed)Amazon Linux 2023, Ubuntu 24.04
Instance typeThe size: vCPUs and memory. Family letter + generation + sizet3.micro: 2 vCPU, 1 GiB
Key pairAWS puts the public key on the server. You keep the private key (a .pem file) and log in with itcht-key.pem
Subnet + security groupWhere it lives and which ports are open (the last lesson)public-a, web-sg
EBS volumeThe server's disk: a network drive that outlives a reboot or stop8 GiB gp3
User dataA script that runs once, as root, on first bootinstall Apache

Which Linux? The families again

Everything in this site comes in two flavours, and EC2 is no different. On AWS, the RHEL family is usually Amazon Linux 2023. It's built from Fedora and CentOS Stream, so it uses dnf, httpd and firewalld-style tools, like Rocky. The Debian family is Ubuntu, straight from Canonical. (Rocky and RHEL images exist too, from their publishers.)

Amazon Linux 2023
aws ssm get-parameter --name \
  /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 \
  --query Parameter.Value --output text

Login user: ec2-user. Packages: dnf. Web server: httpd.

Ubuntu 24.04
aws ssm get-parameter --name \
  /aws/service/canonical/ubuntu/server/24.04/stable/current/amd64/hvm/ebs-gp3/ami-id \
  --query Parameter.Value --output text

Login user: ubuntu. Packages: apt. Web server: apache2.

AMI IDs are different in every region and change with every update, so don't copy them from blog posts. These public SSM parameters always point at the newest image.

User data: set it up on first boot

web.sh for Amazon Linux
#!/bin/bash
dnf install -y httpd
echo "<h1>Hello from $(hostname -s)</h1>" > /var/www/html/index.html
systemctl enable --now httpd
web.sh for Ubuntu
#!/bin/bash
apt-get update
apt-get install -y apache2
echo "<h1>Hello from $(hostname -s)</h1>" > /var/www/html/index.html
systemctl enable --now apache2

cloud-init runs this as root, once, on the very first boot. No sudo needed, and no one is watching, so use -y. Everything it prints goes to /var/log/cloud-init-output.log: the first place to look when a new server doesn't work.

Launch!

aws ec2 create-key-pair --key-name cht-key --query KeyMaterial --output text > cht-key.pem
chmod 400 cht-key.pem                        # ssh refuses keys others could read

ID=$(aws ec2 run-instances --image-id $AMI --instance-type t3.micro \
  --key-name cht-key --subnet-id $SUB --security-group-ids $SG \
  --user-data file://web.sh \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=web-1}]' \
  --query 'Instances[0].InstanceId' --output text)

aws ec2 wait instance-running --instance-ids $ID      # blocks until it's up
IP=$(aws ec2 describe-instances --instance-ids $ID \
  --query 'Reservations[0].Instances[0].PublicIpAddress' --output text)
curl http://$IP
ssh -i cht-key.pem ec2-user@$IP              # ubuntu@$IP on Ubuntu

AWS gives you the private key once. Lose it and you can't log in with that key pair ever again (you'd make a new one and a new server). describe-instances wraps instances in "Reservations" (one per launch request), hence the Reservations[].Instances[] in queries.

Stop, start, terminate

ActionWhat happensYou pay for
stop-instancesShut down, like powering off. The disk stays. The public IP is released, and you get a new one on startthe disk only
start-instancesBoots again (user data does not run again)compute + disk
reboot-instancesA normal reboot. Same IPcompute + disk
terminate-instancesGone for good, and so is its root disknothing more

Need an address that never changes? Allocate an Elastic IP and associate it with the instance. Every public IPv4 address, elastic or not, costs about half a cent an hour, even when it isn't attached to anything.

Instances are cattle, not pets

If a server is broken, the cloud way is to throw it away and launch a fresh one from the same image and user data, not to nurse it back to health. That only works if everything it needs is in the user data or the image, never done by hand. The Auto Scaling lesson makes AWS do the replacing for you.

Practice: your first cloud server 🖥️

The network from the last lesson is ready: VPC cht-vpc, subnet public-a, security group web-sg (22 from your IP, 80 from everywhere). web.sh is in your home folder, written for your family's Linux.

Quick check

1. You stopped an instance overnight and started it again. Why can't you reach it at yesterday's address?

2. Your new server doesn't answer on port 80, but SSH works. Where do you look first?

3. What does chmod 400 cht-key.pem do, and why?

Finished the missions and the quiz? Mark it done to track your progress.