Courses / Hands-on Cloud for Freshers

Session 4 of 8

Your first server: EC2

Overview

Unit 4 — Your First Server: EC2

Course: Hands-on Cloud for Freshers

Prerequisites: You have an AWS account with an everyday administrator identity and a budget alert in place, and you can read a JSON policy and say what it allows (Unit 2). You have published and deleted a static site from S3, and you can read an HTTP status code with curl or a browser (Unit 3). You can type a few commands into a Linux shell — cat, ls, echo — even if you have never administered a server. For the project you also need the AWS CLI version 2 signed in — version 2.32.0 or later if you sign in with aws login. If you are starting here, the notes’ Before you start gives the setup path, and nothing from Unit 3 is required. No prior knowledge of Amazon EC2, security groups or Linux package managers is assumed.

What the reader can do after this unit:

  • Launch an Amazon EC2 instance from an Amazon Linux 2023 image on an instance type that the console marks Free Tier eligible for the reader’s account, with a user data script that installs and starts a web server on first boot.
  • Write the security group rules a public web server needs — HTTP from anywhere, SSH only from the EC2 Instance Connect service — and predict what a browser or a terminal sees when either rule is missing.
  • Say exactly what stopping and terminating an instance each keep, lose and go on charging for, and leave the account with no instance, no orphaned volume and no unused security group.

Core question this unit answers: When you run your own server in the cloud, what do you now have to open, watch and remember to switch off that a storage service like S3 handled for you?

Connections:

  • Builds on: Unit 3’s two locks. A security group plays the barrier’s role for a server, but it is a firewall on network traffic rather than a permission check on objects, and its failure looks different: a browser waits and then gives up instead of receiving a 403.
  • Leads into: Unit 5, which builds the network this unit borrowed. Here the instance runs in the default VPC that every account already has; Unit 5 builds your own VPC, subnet, route table and internet gateway, so that “why does this instance get a public address?” has an answer you wrote.

Your answers are scored

This unit is assessed. The quiz is marked against a key held separately from your materials. Questions 1–8 are multiple choice and are marked by comparing your letter. Questions 9–10 ask you to write something — a user data script and a set of security group rules — and each is marked by running it: the script launches a test instance, and the rules are applied to a test security group and probed with real connection attempts.

Two consequences worth knowing before you start:

  • You can test your constructed answers yourself before you submit them. Every check is printed in the question as an outcome — what must answer, what must stay closed — and you can reproduce each one on your own instance.
  • Only outcomes are marked. Comments, blank lines and the order of your rules do not change your score; a script that stops serving after a reboot does.

Notes

Hands-on Cloud for Freshers — Unit 4: Your First Server: EC2

Before you start

Sign in to the AWS Management Console with your everyday administrator identity and check the Region in the navigation bar. These notes use Asia Pacific (Mumbai), ap-south-1; use a Region near you if you prefer, but stay in that one Region for the whole unit, because an instance, its security group and its volume all live in one Region and the teardown looks only there.

Reading these notes needs nothing installed: you connect to the server from the browser. The project also runs a few AWS CLI commands, so for it you need the AWS CLI version 2 signed in — version 2.32.0 or later if you sign in with aws login, the minimum the AWS CLI User Guide gives for that command.

If you are starting here without the earlier units, set up three things before the project:

  1. A console sign-in that is not the root user and can launch and terminate EC2 instances and edit security groups — an identity with administrator permissions is enough.
  2. The AWS CLI. Install or update it by following Installing or updating to the latest version of the AWS CLI (Sources), then run aws --version; the output starts aws-cli/<version>, and the version must be 2.32.0 or higher for the next step.
  3. The CLI signed in. Run aws login, finish the sign-in in the browser it opens, and choose your Region when it asks. The sign-in guide lists the SignInLocalDevelopmentAccess managed policy among its prerequisites for the identity. Then run aws sts get-caller-identity: it prints your account ID and the ARN of the identity you signed in as. An error means step 3 is not done.

You do not need anything from Unit 3. These notes compare a server with the S3 website you would have built there, and the one fact that comparison needs is stated where it is used. If you did Unit 3, its evidence table is a useful side-by-side, but nothing here asks you for it.

Every resource you create carries the tag project = hands-on-cloud.

Cost, before anything else. An EC2 instance is the first resource in this course that is charged for as long as it runs, whether or not anyone uses it, and it keeps running until you stop or terminate it. Two separate facts decide what that costs you:

  • Credits are a balance your usage draws on. The AWS Billing guide says a new account receives USD 100 in credits whichever plan it chooses, and that the credits are applied automatically to cover eligible costs beyond the always-free allowances. On the Free account plan you incur no charges until you upgrade to a paid plan, and the plan ends after six months or when the credits are used up, whichever comes first — so an instance left running spends credits every other unit also needs. On the Paid account plan, usage beyond your credits is charged at standard rates.
  • Some instance types are marked Free Tier eligible. That label is the EC2 Free Tier benefit, and the EC2 User Guide lists the types it covers by account creation date. For accounts created on or after 15 July 2025: t3.micro, t3.small, t4g.micro, t4g.small, c7i-flex.large and m7i-flex.large; for older accounts, t2.micro and t3.micro. These notes use t3.micro, which is on both lists, and the console’s own Free Tier eligible label is the authority for your account.

Every statement here about how EC2 behaves is taken from the Amazon EC2 User Guide, the Amazon EBS User Guide, the Amazon VPC User Guide and the AL2023 User Guide, fetched 2026-10-02; the pages are listed under Sources at the end.

Summary

Amazon EC2 rents you a virtual server — an instance — that runs the operating system you choose, on a network you control, with a disk that outlives a restart. That freedom is the whole difference from Unit 3: S3 served your page with no server at all, whereas an instance has to be launched from an image, given a firewall that lets the right traffic in, and have its software installed. It also has to be stopped or terminated — the part people forget — because it is charged for every moment it runs, and even a stopped instance keeps a disk that is still billed. This unit launches one instance with a script that installs a web server on first boot, and opens exactly two doors in its firewall: web traffic from anyone, and administrator access only from the browser-based connection service. You then connect to it and take it apart, checking what each step keeps, loses and still charges for.

Key concepts

Term Definition
Instance A virtual server in the AWS Cloud, launched from an image, with an instance type, a network and a root volume
AMI (Amazon Machine Image) A template containing the software an instance starts with, including its operating system. These notes use the Amazon Linux 2023 (AL2023) image
Instance type The size of the virtual hardware: processor, memory and network capacity. Only some types are marked Free Tier eligible for a given account
EBS volume A network-attached disk. Every instance in this unit has an EBS root volume, which keeps its data when the instance stops
Security group A virtual firewall attached to an instance. Its inbound rules list the traffic allowed in; anything not listed is not allowed in. It is stateful, so replies to allowed traffic are allowed back out
Default VPC A virtual network AWS creates in each Region of your account, with a default subnet in each Availability Zone. An instance launched into it gets a public IPv4 address by default
Public IPv4 address An address reachable from the internet. An automatically assigned one is released when the instance stops or terminates, and a new one is assigned on start. AWS charges for all public IPv4 addresses
User data Text passed to an instance at launch. A shell script starting with #! runs as the root user on the first boot only, by default
EC2 Instance Connect A way to open an SSH connection from the console in your browser. It pushes a temporary public key to the instance for 60 seconds, authorised by IAM, so you do not manage SSH keys yourself
Prefix list A named set of IP address ranges that a security group rule can use as its source. AWS publishes one for the EC2 Instance Connect service in each Region
Stop Shut the instance down but keep it, its root volume and its private address. Instance usage charges stop; the volume is still charged
Terminate Delete the instance permanently. A root volume attached at launch is deleted with it by default

Explanations

Four situations, before any design table

Every table later in this section is a set of choices — what to pick on the launch page, which doors to open, whether to stop or terminate. Each choice exists because of a situation like one of these four, so meet them first.

1. The page that never answers. You launch an instance, wait for its state to show running, copy its public DNS name, and paste it into a browser with http:// in front. The browser spins. Nothing comes back — no error page, no status code, nothing — until it gives up and tells you the site cannot be reached.

Compare that with a static website served from Amazon S3 (Unit 3). There, S3 always answers: its website endpoint returns 403 Forbidden for a page that exists but is not publicly readable, which tells you it found your file and refused to hand it over. Here, nothing answers at all. That silence is the clue. The request never reached your web server, because something in front of the server dropped it without a word.

That something is the security group, and the default one the launch wizard creates allows only SSH on port 22. Web traffic on port 80 is not on the list, so it does not get in. The fix is one inbound rule.

2. The door left open to everyone. You accept the defaults on the launch page and the instance works. Later you look at its security group and find SSH on port 22 allowed from 0.0.0.0/0 — from any address on the internet — because that is the rule the launch wizard creates. You tighten the source to My IP, and now connecting with EC2 Instance Connect from the console stops working. Both the open door and the broken connection come from choosing a rule’s source without knowing where the traffic actually comes from.

3. The server nobody can rebuild. You connect to an instance and type the commands that install and start a web server, one by one. It works. Then the instance is terminated, and the commands you typed by hand are lost with it; the next server starts without them and has to be set up again from memory.

4. The instance you stopped instead of removing. You finish an exercise and choose Stop, because it sounds safe. The instance no longer runs, but its disk is still charged. And when you start it again, the public address you bookmarked no longer reaches it: the instance comes back with a different one.

The rest of this section answers these in order: what an instance is and how to launch one, how user data installs the software for you (situation 3), which doors to open and from where (situations 1 and 2), and what stop and terminate keep, lose and still charge for (situation 4).

An instance is a computer you rent while it runs

Think of renting a flat rather than using a self-service locker. A locker (S3 in Unit 3) holds your things and hands them over; there is nothing inside to maintain. A flat (an EC2 instance) is yours to furnish, lock, heat and clean — and the rent runs whether you are home or not.

A second way to see it: an instance is a laptop someone else plugged in for you. You pick the operating system (the AMI), the size of the laptop (the instance type), its hard disk (the EBS root volume) and which cables are connected (the network and security group). After that, everything that happens on the laptop is your responsibility.

Launching one in the console goes through a single page, Launch instances:

Section of the launch page What to choose in this unit Why
Name and tags Name hoc-web Lets you find it; add the project tag after launch
Application and OS Images (Amazon Machine Image) Quick Start, Amazon Linux, an AL2023 AMI marked Free Tier eligible The standard AL2023 AMI comes with EC2 Instance Connect preinstalled
Instance type t3.micro, marked Free Tier eligible On the eligible list for new accounts
Key pair (login) Proceed without a key pair (Not recommended) You will connect with EC2 Instance Connect from the browser, which pushes its own temporary key — see below
Network settings Default VPC and subnet; create a security group The default security group rule allows SSH from anywhere; you will tighten it
Configure storage Leave the single root volume Enough for a test web server
Advanced details, User data The script below Installs the web server on first boot

About the key pair: the console labels proceeding without one “Not recommended” because, without a key pair, you cannot log in with an ordinary SSH client from your own terminal. EC2 Instance Connect does not need one — it pushes a temporary public key to the instance at the moment you connect — and that is the only way this unit connects. If you would rather also try an SSH client, create a key pair instead; nothing else in the unit changes.

Tagging after launch. Once the instance exists, add the course tag either in the console — select the instance, open the Tags tab, choose Manage tags, then Add new tag, enter the key and value, and choose Save — or with one CLI command, using your instance’s ID:

aws ec2 create-tags --resources i-0a1b2c3d4e5f67890 --tags Key=project,Value=hands-on-cloud

--resources names what to tag; --tags takes Key= and Value= joined by a comma, with no spaces. Tag keys are case sensitive, so Project and project are two different tags — use the lower-case one the teardown looks for. If the command succeeds, it prints nothing.

User data: install the software before you ever log in

You could launch the instance, connect, and type the installation commands by hand. That works once. User data lets you hand the instance a script that runs on its first boot, so the server comes up already doing its job.

#!/bin/bash
dnf install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from hoc-web</h1>" > /var/www/html/index.html

Line by line:

  • #!/bin/bash — a user data shell script must start with #! and the path to its interpreter.
  • dnf install -y httpd — installs the Apache web server on AL2023. The -y matters: the script is not run interactively, so a command that waits for confirmation would wait forever.
  • systemctl start httpd starts the web server now; systemctl enable httpd makes it start on every later boot.
  • The echo line writes your homepage into Apache’s document root on Amazon Linux, /var/www/html.

Notice what is not there: sudo. The EC2 User Guide says user data scripts run as the root user, so you do not use sudo in them. That is the opposite of what you type when you connect by hand, where AL2023’s tutorial prefixes the same commands with sudo.

Two more facts from the same guide decide how you debug this:

  • It runs once. By default, user data scripts run only during the first boot. Editing the user data of a stopped instance and starting it again does not re-run the script.
  • It leaves a log. Its output is captured in /var/log/cloud-init-output.log on the instance. When the page does not appear, that file says whether the install failed or never ran.

Security groups: the doors in the firewall

A security group is a guest list on the door. Anyone whose traffic matches an inbound rule is let in; anyone else is turned away without being told. And it is a stateful list: once a visitor is let in, the reply to that visitor goes back out without needing its own rule. The EC2 User Guide puts it exactly that way — responses to allowed inbound traffic are allowed to flow out, regardless of outbound rules.

A second way to see it: a security group is a list of open windows in a wall, each labelled with the port it opens and who may climb through. Port 80 is the HTTP window; port 22 is the SSH window.

This unit’s web server needs two rules, and the reason for each source is different:

Type Port Source Why this source
HTTP 80 Anywhere-IPv4 (0.0.0.0/0) A public web page must be reachable by anyone
SSH 22 The prefix list com.amazonaws.ap-south-1.ec2-instance-connect When you connect from the console, the traffic comes from the EC2 Instance Connect service, not from your own computer

The second row is where most people go wrong, and the failure is instructive. The launch wizard’s default rule allows SSH from anywhere (0.0.0.0/0). The EC2 documentation calls that acceptable only for a short time in a test environment. The obvious tightening is to change the source to My IP — and then EC2 Instance Connect from the console stops working, because the connection arrives from the service’s addresses, not yours. The documented rule for console connections is a source of the EC2 Instance Connect prefix list for your Region.

To change it: in the console choose Security Groups, select the group, and choose Edit inbound rules. You cannot change an existing rule’s source from an address range to a prefix list — the console does not allow the source type to change — so delete the SSH rule, choose Add rule, pick type SSH, set the source to Custom and select the prefix list, then choose Save rules. Changes apply immediately to every instance using the group.

What stops, what stays, what still costs

Think of a hotel room. Checking out for the day but keeping the booking is stop: the room is still yours, your luggage stays in it, and you keep paying for the room. Checking out for good is terminate: the room goes back, and so does anything you left in it. EC2 makes the same split:

Stop Terminate
Instance Kept, in state stopped Deleted permanently; shown as terminated for a while, then gone
Instance usage charges Stop Stop
EBS root volume Kept, with its data, and still charged Deleted by default if it was attached at launch
Data in memory (RAM) Lost Lost
Automatically assigned public IPv4 address Released; a new one is assigned on start Released
Private IPv4 address Kept Released

Two rows decide your bill and your bookmarks:

  • A stopped instance is not free. Its EBS volume is still charged. Stop is for “I need this again tomorrow”; terminate is for “I am done”.
  • Your address changes. Stop and start the instance and the public IPv4 address you bookmarked belongs to the pool again; the instance comes back with a different one. A fixed address needs an Elastic IP address, which is outside this unit.

And one row that is easy to miss entirely: public IPv4 addresses are charged — every one, including the one on a running instance. The EC2 User Guide’s own cost formula prices a public IPv4 address at USD 0.005 per hour. On the Free account plan this comes out of your credits like everything else, which is one more reason not to leave an instance running overnight by accident.

Taking it down in the right order

Clearing out a rented flat goes in an order: you move out the furniture before you return the keys to the doors that let it in. Here, terminate first, then delete what was attached to it. A security group cannot be deleted while it is associated with an instance, so the order is not optional.

  1. Instances → select hoc-web → Instance state → Terminate (delete) instance → Terminate (delete). Wait until its state is terminated.
  2. Volumes → check that no volume from this instance remains. A root volume attached at launch is deleted with the instance by default; anything left in the available state is a disk attached to nothing and still charged.
  3. Security Groups → select the group the launch wizard created → Actions → Delete security groups → Delete. You cannot delete the VPC’s default security group, and you do not need to. If the delete is refused, look for what still uses the group: the EC2 User Guide’s requirements are that it is associated with no instance or network interface and referenced by no rule in another security group. Here the usual cause is an instance that has not finished terminating.

Flashcards

Say the answer aloud before revealing it. Speaking it is what exposes the gaps that reading past a written answer hides. Choose a question to reveal its answer.

What is the difference between an AMI and an instance type?

The AMI is the software the instance starts with, including its operating system. The instance type is the size of the virtual hardware it runs on.

How do you know which instance types are free-tier eligible for your account?

The launch page marks them Free Tier eligible. The list depends on whether the account was created before or on and after 15 July 2025.

Your browser spins and then says the site cannot be reached, but the instance is running. What do you check first?

The security group’s inbound rules: is there a rule for HTTP on port 80? Silence means the traffic never reached the server.

Why does a user data script not use sudo?

User data scripts run as the root user already.

You edited the user data of a stopped instance and started it. Why did nothing change?

By default user data runs only on the first boot of the instance.

Where do you look when a user data script seems not to have worked?

/var/log/cloud-init-output.log on the instance.

You allowed inbound HTTP. Do you also need an outbound rule for the replies?

No. Security groups are stateful: replies to allowed inbound traffic are allowed out regardless of outbound rules.

Why does setting the SSH source to My IP break EC2 Instance Connect from the console?

The console connection arrives from the EC2 Instance Connect service’s address ranges, not from your computer. The rule needs the service’s prefix list as its source.

What keeps costing money while an instance is stopped?

Its EBS volumes are still charged. Instance usage charges stop.

Why did your bookmarked IP address stop working after a stop and start?

An automatically assigned public IPv4 address is released on stop, and a new one is assigned on start.

What happens to the root volume when you terminate an instance?

If it was attached at launch, it is deleted with the instance by default.

Why can't you delete the security group before terminating the instance?

A security group cannot be deleted while it is associated with an instance.

Model answer

The question: “You’ve put a small web page on an EC2 instance. Walk me through how you launched it, how people reach it, and how you make sure it isn’t quietly costing money next month.”

There are five beats, and they should come in this order. Missing any one of them is a failure state, not a stylistic gap.

  1. What you launched, and why that type. An Amazon Linux 2023 AMI on an instance type the console marked Free Tier eligible for the account, in the default VPC, with a public IPv4 address.
  2. How the software got there. A user data script that installs, starts and enables the web server on first boot — run as root, so no sudo, and with -y so nothing waits for input — and the log you read when it does not work.
  3. Which doors you opened, and from where. HTTP on port 80 from anywhere, SSH on port 22 only from the EC2 Instance Connect prefix list — and why My IP would have broken the console connection. Saying “I opened the ports” without naming the sources is not this beat.
  4. What you would check if it failed. Silence in the browser means the security group; a running server with no page means the user data log. Naming the symptom-to-cause link is the beat.
  5. How it stops costing money. Terminate rather than stop when finished, because a stopped instance’s volume is still charged; confirm no volume is left available; delete the security group after the instance is gone; and remember that public IPv4 addresses are charged while they exist.

Beat five is the one most answers drop, and it is the one that matters most to whoever pays the bill.

Why this matters

  • The bill that arrived for a demo nobody used. An instance launched for a workshop exercise was stopped rather than terminated. Its volume kept being charged. Knowing the stop/terminate table by heart is what prevents this.
  • A server that worked on Friday and not on Monday. It was stopped over the weekend and started again with a new public address; every bookmark and every hard-coded link pointed at the old one.
  • SSH open to the whole internet. The launch wizard’s default rule allows SSH from anywhere. Narrowing it to the EC2 Instance Connect prefix list keeps the console connection working while closing the door to everyone else.
  • A setup nobody can repeat. Commands typed by hand into one server are lost when it is terminated. A user data script is the first step towards a server you can rebuild on demand — the idea Unit 8 builds on.

After this unit

The project for this unit is Launch, Lock Down and Remove a Web Server (project.md). You will launch hoc-web with a user data script, observe the silent failure and fix it with one rule, replace the wide SSH rule with the EC2 Instance Connect prefix list and prove the console connection still works, watch the public address change across a stop and start, and finish with an account that has no instance, no leftover volume and no unused security group.

Unit 5 builds the network this unit borrowed: your own VPC, a public subnet, a route table and an internet gateway, so that the public address your instance received here is something you set up rather than something that happened by default.

Sources

Every page below was fetched 2026-10-02.

Project

Hands-on Project — Launch, Lock Down and Remove a Web Server

Objective

Launch an EC2 web server that configures itself on first boot, find out for yourself why a browser cannot reach it, fix that, narrow its SSH access to exactly what the console connection needs, and then remove it so completely that nothing tagged for this course is left running. You finish with a log of what you observed at each step, and a short card of settings that Unit 5 builds on.

What you need: your AWS account, signed in to the console as your everyday administrator identity; the AWS CLI version 2, signed in — version 2.32.0 or later if you sign in with aws login, the minimum the AWS CLI User Guide gives for that command (check with aws --version); and curl (or a browser) to request pages. Every resource this project creates, changes or deletes is in Amazon EC2, and it needs no paid feature. Two commands look at other services without creating anything: aws sts get-caller-identity (AWS STS), which shows who the CLI is signed in as, in the setup steps below; and, only if you kept an S3 site bucket from Unit 3, aws s3api head-bucket (Amazon S3), which checks in Task 1, step 1 that the bucket exists and that you can access it.

  • Cost. EC2 charges for an instance while it runs, for its EBS volume until the volume is deleted — including while the instance is stopped — and for every public IPv4 address. Those charges draw on your account’s credits: on the Free account plan, AWS’s billing guide states you incur no charges until you upgrade, and the plan ends when the credits are used up or after six months. Separately, the EC2 User Guide lists the instance types marked Free Tier eligible by account creation date, and t3.micro is on both lists. Do the teardown even if you stop early.

  • If you are starting here. You need a console sign-in that is not the root user and can launch and terminate EC2 instances and edit security groups — an identity with administrator permissions is enough — and the CLI signed in as it:

    1. Install or update the AWS CLI by following Installing or updating to the latest version of the AWS CLI (Sources). Run aws --version; the output starts aws-cli/<version>, and the version must be 2.32.0 or higher.
    2. Run aws login and finish the sign-in in the browser it opens. The sign-in guide lists the SignInLocalDevelopmentAccess managed policy among its prerequisites for the identity.
    3. Run aws sts get-caller-identity. It must print your account ID and the ARN of the identity you signed in as; if it prints an error, repeat step 2.

    Nothing from Unit 3 is needed: Task 1, step 1 has a line for readers with no earlier bucket.

Throughout, use your own Region in place of ap-south-1, and your own IDs in place of the examples: instance i-0a1b2c3d4e5f67890, security group sg-0123456789abcdef0 and volume vol-0123456789abcdef0.


How to write your log

Everything you record goes in one plain-text file, hoc-web-log.txt, written in the line shapes each task’s Output gives. Every line starts with the label shown, then a colon and a space; the parts in <angle brackets> are what you fill in, without the brackets. Where a command prints nothing, write (empty). Where it prints more than one line, join the lines with single spaces so the value stays on one line, unless the shape says to paste the output as it is.


Task 1 — Start clean, then launch a server that configures itself

Scope: one instance, one script, default network. Stop once the instance is running and tagged.

  1. Start your log from a clean slate. Everyone does this step the same way, whether or not you did the earlier units. Run these three checks. Each lists something tagged for this course that an earlier attempt may have left behind — an instance that is not terminated, a disk volume, a security group:

    aws ec2 describe-instances \
        --filters Name=tag:project,Values=hands-on-cloud \
                  Name=instance-state-name,Values=pending,running,stopping,stopped \
        --query "Reservations[].Instances[].InstanceId" --output text
    
    aws ec2 describe-volumes \
        --filters Name=tag:project,Values=hands-on-cloud \
        --query "Volumes[].[VolumeId,State]" --output text
    
    aws ec2 describe-security-groups \
        --filters Name=tag:project,Values=hands-on-cloud \
        --query "SecurityGroups[].GroupId" --output text

    Record the first check’s output as your clean-slate ec2 line. If all three print nothing, go straight to the bucket line below. If any of them lists something, remove it before you go on, in this order, using the IDs it printed:

    1. Each instance ID from the first check. Terminate it, then wait for the termination to finish:

      aws ec2 terminate-instances --instance-ids i-0a1b2c3d4e5f67890
      aws ec2 wait instance-terminated --instance-ids i-0a1b2c3d4e5f67890

      The wait checks every 15 seconds and returns with no output once the instance is terminated. If it exits with return code 255 instead, it gave up after 40 checks: run it again.

    2. Each volume from the second check. Run the second check again, because terminating an instance deletes the root volume attached at launch by default, and read each volume’s state:

      • available — the volume is attached to nothing and is still charged. Delete it: aws ec2 delete-volume --volume-id vol-0123456789abcdef0. On success it prints nothing.
      • in-use — it is still attached to an instance. Finish sub-step 1 for that instance first.
      • deleting — its deletion is under way, which can take several minutes. Leave it.
    3. Each group ID from the third check. Delete it: aws ec2 delete-security-group --group-id sg-0123456789abcdef0. If it fails with DependencyViolation, the group is still associated with an instance or network interface, or referenced by another security group; here the usual cause is an instance that has not finished terminating, so finish sub-step 1 and run the delete again.

    4. Check the slate is clean. Run the three checks again. Go on only when the first and third print nothing and the second prints nothing or only volumes in the state deleting.

    For the bucket line, choose the one that fits you:

    • You still have an S3 site bucket from Unit 3 and know its name: run aws s3api head-bucket --bucket <that bucket name>, and straight after it display the command’s return code with echo $? on Linux or macOS, echo $lastexitcode in Windows PowerShell, or echo %errorlevel% in the Windows Command Prompt. Return code 0 means the service answered with no error; any other code means the command failed, which is still a valid result to record.
    • You never made one, or do not know its name: your line is no earlier bucket to check. Nothing in this project depends on it.
  2. Save this script as hoc-web-userdata.sh on your computer:

    #!/bin/bash
    dnf install -y httpd
    systemctl start httpd
    systemctl enable httpd
    echo "<h1>hoc-web-ok</h1>" > /var/www/html/index.html
  3. In the EC2 console, check the Region, then choose Launch instance. Set:

    • Name and tags → Name hoc-web;
    • Application and OS Images → Quick Start, Amazon Linux, an AL2023 AMI marked Free Tier eligible;
    • Instance type → t3.micro, or another type the page marks Free Tier eligible for you;
    • Key pair (login) → Proceed without a key pair (Not recommended);
    • Network settings → keep the default VPC and subnet, and let the wizard create a security group with its default SSH rule;
    • Advanced details → User data → paste the script.

    Then choose Launch instance.

  4. Open the instance from the success message. Wait until its state is running and its status checks have passed. Passing status checks does not prove your script has finished: the EC2 User Guide says tasks added at boot make booting take longer, and to allow extra time for them before you test. You check that the script finished in Task 2, step 2. Note its instance ID, public IPv4 address, public IPv4 DNS name, the ID of the security group the wizard created (on the Security tab), and the ID of the root volume (on the Storage tab, under Block devices).

  5. Tag the instance, its security group and its root volume, using your IDs. Tagging the volume is what lets the clean-slate check in step 1 find it if it is ever left behind:

    aws ec2 create-tags \
        --resources i-0a1b2c3d4e5f67890 sg-0123456789abcdef0 vol-0123456789abcdef0 \
        --tags Key=project,Value=hands-on-cloud

    On success it prints nothing. Check the result:

    aws ec2 describe-tags --filters \
        Name=resource-id,Values=i-0a1b2c3d4e5f67890,sg-0123456789abcdef0,vol-0123456789abcdef0

    The output must list, for each of your three IDs, an entry with Key project and Value hands-on-cloud. If an ID has no such entry, check that you copied it correctly, run create-tags again for it, and repeat the check.

Time budget: 30 minutes

Output: these lines in hoc-web-log.txt, in this order, followed by the describe-tags output pasted as it is:

clean-slate ec2: <the first check's output from step 1, or (empty)>
clean-slate bucket: <the head-bucket output, or (empty)> | exit <return code>
instance: <instance ID>
public-ip: <public IPv4 address>
public-dns: <public IPv4 DNS name>
security-group: <security group ID>
root-volume: <root volume ID>
describe-tags:

If you had no earlier bucket, your second line is clean-slate bucket: no earlier bucket to check.


Task 2 — Find out why the page does not load, fix it, then lock down SSH

Scope: two rule changes and four observations. Stop when every line of the Output below is filled.

  1. Predict, then request. Write down what you expect, then run:

    curl -s -o /dev/null -w "%{http_code}\n" --max-time 10 http://<public DNS name>/

    --max-time 10 sets the most time, in seconds, that curl allows the whole request to take, so the command cannot hang. Record exactly what it printed.

  2. Connect and look. Select the instance, choose Connect, choose the EC2 Instance Connect tab, choose Connect using a Public IP, check that Username is ec2-user, and choose Connect. In the browser terminal, first check that your user data script ran to its end. Its last line writes the homepage, so the homepage file exists only once the script has finished:

    cat /var/www/html/index.html
    • It prints <h1>hoc-web-ok</h1>: the script finished. Record finished and carry on below.

    • It says No such file or directory: the script has not finished yet. Wait, then run the same command again. Check up to three times.

    • Still no file after the third check, or httpd below is not active: read the script’s log with sudo tail -n 30 /var/log/cloud-init-output.log and note any error line. Then do by hand what the script should have done, with sudo because you are now ec2-user rather than root:

      sudo dnf install -y httpd
      sudo systemctl start httpd
      sudo systemctl enable httpd
      echo "<h1>hoc-web-ok</h1>" | sudo tee /var/www/html/index.html

      Run cat /var/www/html/index.html again; it must now print <h1>hoc-web-ok</h1>. Record repaired by hand, with the error line or the reason.

    Now run:

    systemctl is-active httpd
    systemctl is-enabled httpd
    curl -s http://localhost/

    Record the three results: you are looking for active, enabled and the homepage text. If any differs, go back to the by-hand repair above. Then decide, in one sentence, what they tell you about where the problem from step 1 is — on the instance, or in front of it.

  3. Open the web door. Choose Security Groups, select the group the wizard created, choose Edit inbound rules, choose Add rule, set Type to HTTP and the source to Anywhere-IPv4, and choose Save rules. Repeat the curl from step 1 and record the code. Open the address in a browser and record the text the page shows. The page should now load and show hoc-web-ok; if it does not, reopen Edit inbound rules, check that the HTTP rule was saved with port 80 and source 0.0.0.0/0, and check that you requested http://, not https://, then request it again.

  4. Narrow the SSH door. Edit inbound rules again. Delete the SSH rule whose source is 0.0.0.0/0. Choose Add rule, set Type to SSH, set the source to Custom and select the prefix list com.amazonaws.ap-south-1.ec2-instance-connect (with your Region’s code), and choose Save rules. Check the group’s Inbound rules tab: it must now list exactly two rules, HTTP from 0.0.0.0/0 and SSH from the prefix list. If the old SSH rule is still there, delete it and save.

  5. Test the console connection again. Connect with EC2 Instance Connect exactly as in step 2, and record whether a terminal opened. If it did not, check that the SSH rule’s prefix list carries the same Region code as the Region your instance is in, correct it if not, and connect again.

Time budget: 45 minutes

Output: these lines in hoc-web-log.txt, in this order, then one rule line for each inbound rule the group has at the end of step 5:

step 1: predicted <your prediction> | observed <what curl printed>
step 2: index <what your last cat of index.html printed> | script <finished|repaired by hand — the error line or reason> | is-active <result> | is-enabled <result> | localhost <result> | problem <on the instance|in front of it> — <your one sentence>
step 3: code <what curl printed> | page <the text the browser showed>
step 4: saved <yes|no>
step 5: terminal opened <yes|no>
rule: <protocol> <port> <source>

Write each rule line’s protocol in lower case as the console’s Protocol column shows it, the port as a number, and the source as the console shows it: an address range such as a CIDR block, or, for a prefix list, its name — not its pl- ID.


Task 3 — Watch the address move (optional extension)

Scope: one stop, one start, two addresses. Stop once both addresses are recorded.

  1. Note the current public IPv4 address. Choose Instance state → Stop instance → Stop, and wait for stopped. Record what the console now shows for the public IPv4 address.
  2. Choose Instance state → Start instance, wait for running and for the status checks to pass, as in Task 1, step 4, and record the public IPv4 address. Request the old address with the curl command from Task 2, then the new one, and record both codes. Your web server was enabled to start at boot in Task 2, so the new address should serve the page; if it does not, connect as in Task 2, step 2, run systemctl is-active httpd, and if it is not active, run sudo systemctl start httpd and request the new address again.
  3. Write two sentences: what changed and why, and what was still being charged while the instance was stopped. Base both sentences on what you recorded in steps 1 and 2 and on How EC2 instance stop and start works (in Sources).

Time budget: 20 minutes

Output: these lines in hoc-web-log.txt:

before-stop: <public IPv4 address before the stop>
while-stopped: <what the console showed for the public IPv4 address>
after-start: <public IPv4 address after the start>
old-address-code: <what curl printed for the old address>
new-address-code: <what curl printed for the new address>
why: <your two sentences>

Task 4 — Teardown and carry-forward card (required)

Do this whether or not you finished every task. Use the instance, security group and root volume IDs from your Task 1 lines.

  1. Terminate the instance. Instances → select hoc-web → Instance state → Terminate (delete) instance → Terminate (delete). Then wait for the termination to finish:

    aws ec2 wait instance-terminated --instance-ids i-0a1b2c3d4e5f67890

    It returns with no output once the instance is terminated. If it exits with return code 255, it gave up after 40 checks, 15 seconds apart: run it again.

  2. Check the root volume, and remove it if it survived. Run:

    aws ec2 describe-volumes --volume-ids vol-0123456789abcdef0 \
        --query "Volumes[].[VolumeId,State]" --output text
    • An error naming InvalidVolume.NotFound: the volume does not exist — it was deleted with the instance, which is the default for a root volume attached at launch. Nothing to do.
    • State deleting: its deletion is under way, which can take several minutes. Run the command again later.
    • State available: the volume survived and, attached to nothing, is still charged. Delete it: Volumes → select the volume and check that it shows Available → Actions → Delete volume → enter delete → Delete. Or run aws ec2 delete-volume --volume-id vol-0123456789abcdef0. Then run the check again.
    • State in-use: it is still attached, so the instance has not finished terminating. Finish step 1, then run the check again.
  3. Delete the security group. Security Groups → select the group you tagged → Actions → Delete security groups → Delete. Or run aws ec2 delete-security-group --group-id sg-0123456789abcdef0. A security group cannot be deleted while it is associated with an instance or network interface, or referenced by a rule in another security group; the CLI then reports DependencyViolation. If the delete is refused, finish step 1, check those three things, and delete again.

  4. Prove nothing tagged is left. Run each command and record its output:

    aws ec2 describe-instances \
        --filters Name=tag:project,Values=hands-on-cloud \
                  Name=instance-state-name,Values=pending,running,stopping,stopped \
        --query "Reservations[].Instances[].InstanceId" --output text
    
    aws ec2 describe-volumes --volume-ids vol-0123456789abcdef0 \
        --query "Volumes[].[VolumeId,State]" --output text
    
    aws ec2 describe-security-groups \
        --filters Name=tag:project,Values=hands-on-cloud \
        --query "SecurityGroups[].GroupId" --output text

    Use your root volume ID in the second command; if it reports an error instead of a volume, record the error message. If the first or third command lists anything, or the second shows available or in-use, go back to the step that removes it and then run this step again.

  5. Write the carry-forward card. Three lines: your final inbound rules from Task 2, written exactly as your Task 2 rule lines, and the path of your hoc-web-userdata.sh.

Output: these lines in hoc-web-log.txt:

teardown instances: <the first command's output, or (empty)>
teardown volume: <the second command's output, or its error message>
teardown security-groups: <the third command's output, or (empty)>
card-rule: <protocol> <port> <source>
card-rule: <protocol> <port> <source>
card-script: <the path of your hoc-web-userdata.sh>

What this feeds

Unit 5 opens by building, by hand, the network this project borrowed from the default VPC. Its first instance uses the same two inbound rules as your carry-forward card — HTTP from anywhere, SSH only from the EC2 Instance Connect prefix list — and the same kind of first-boot web server script, so you start Unit 5 with both written down and with a tag check that shows nothing from this unit is still running.


Sources

Every page below was fetched 2026-10-02.

Quiz

Online marking is not open yet. Work through the questions and check the written ones against the criteria printed with each question. The answer key is kept back for now.

Quiz — Unit 4: Your First Server: EC2

Instructions: Ten questions in two parts, and both parts are scored.

  • Questions 1–8 are multiple choice. Pick one option per question. They are marked by comparing your letter against the key.
  • Questions 9–10 ask you to write something: a user data script and a set of security group rules. Each is marked by what your answer does when it is applied to a real test instance, not by how its text compares with anyone else’s.

Work closed-book on questions 1–8. On questions 9–10 you may test your answer on your own instance as often as you like before submitting it. The answer key is held separately.

Every question uses the Asia Pacific (Mumbai) Region, ap-south-1, and an Amazon Linux 2023 instance named hoc-web.


1. Your AWS account was created in 2026, after 15 July 2025. According to the EC2 User Guide, which of these instance types is marked Free Tier eligible for your account?

a) t2.micro b) m7i.large c) t4g.micro d) t2.nano


2. You stop hoc-web instead of terminating it and leave it stopped. What goes on being charged?

a) The EBS root volume, which persists with its data while the instance is stopped b) The instance usage, at a reduced rate, until the instance is terminated c) The security group, which is billed for each instance it remains attached to d) The automatically assigned public IPv4 address, which stays reserved for you


3. You bookmarked http://<public IPv4 address of hoc-web>/. After you stop and start the instance, the bookmark no longer reaches it. Why?

a) Starting an instance re-runs its user data, which reinstalls the web server on another port b) The security group’s rules are cleared on stop and must be added again after every start c) A stopped instance moves to a new Availability Zone, and each zone uses its own addresses d) The public IPv4 address was released on stop, and a new one was assigned when it started


4. To tighten SSH, you changed the inbound rule’s source from 0.0.0.0/0 to My IP. Now Connect → EC2 Instance Connect in the console fails. Why?

a) EC2 Instance Connect needs a key pair, and changing the rule removes the one the wizard created b) Console connections arrive from the EC2 Instance Connect service’s prefix list, not your address c) EC2 Instance Connect uses port 443 to reach the instance, so the SSH rule was never relevant d) Your address is IPv4 but the console connects over IPv6, so My IP can never match it


5. hoc-web is running, and connecting with EC2 Instance Connect shows that httpd is active. A browser pointed at http://<public DNS name>/ spins and then reports that the site cannot be reached. What is the most likely cause?

a) The security group has no inbound rule allowing HTTP on port 80 b) The security group has no outbound rule allowing replies on port 80 c) The instance needs an Elastic IP address before it can serve web traffic d) The page must be requested with https://, because port 80 is closed by default on AL2023


6. You stopped hoc-web, edited its user data to write a new homepage, and started it again. The old homepage is still served. Why?

a) User data edits take effect only after the instance has been terminated and launched again b) The console cached the old script, and the new one must be base64-encoded before it is saved c) By default, user data scripts run only during the first boot of a newly launched instance d) The new script needs sudo before the echo, because the web root is owned by root


7. Your security group allows inbound HTTP on port 80 from anywhere, and has its default outbound rule. Do you need to add anything so that visitors receive the page in reply?

a) Yes: an outbound rule for port 80 to 0.0.0.0/0, or replies are dropped at the group b) No: security groups are stateful, so replies to allowed inbound traffic are allowed out c) Yes: an inbound rule for the ephemeral ports, which the replies use to come back in d) No: outbound traffic is never filtered by a security group, whatever its rules say


8. You launched hoc-web with the default storage settings and then terminated it. What happened to its root volume?

a) It was kept in the available state, so that the instance’s data can be recovered later b) It was detached and kept, and is deleted only when its security group is deleted c) It was converted to a snapshot automatically, which is charged until you delete it d) It was deleted, because a root volume attached at launch is deleted by default on termination


Part 2 — Constructed response

Submit only the requested text — no explanation, no surrounding quotes.


9. Write the user data script for hoc-web that, with nobody logged in, turns a fresh Amazon Linux 2023 instance into a web server whose homepage contains the text hoc-web-ok, and keeps serving it after a reboot.

Your script is pasted into User data when launching a t3.micro AL2023 instance in a security group that allows HTTP from anywhere. Nobody connects to the instance at any point.


10. Write the complete set of inbound rules for hoc-web’s security group in ap-south-1, so that anyone can load the web page, console connections with EC2 Instance Connect keep working, and nothing else gets in.

Write one rule per line, in the form <protocol> <port> <source>, all lower case, where <source> is either an IPv4 CIDR block or the name of a prefix list. For example, a rule allowing HTTPS from anywhere is written tcp 443 0.0.0.0/0.

Your rules replace every inbound rule of the group. Every line must be exactly three words and a rule the EC2 console would accept.


Sources

These questions are taught in this unit’s notes, which draw on these pages:

TechEazy Consulting training material — not affiliated with or endorsed by Amazon Web Services (AWS).