Introduction
Your team wants to stop a report server during maintenance and bring it back with a predictable public address. You will operate an EC2 instance, compare its stopped and running states, associate an Elastic IP and check the application after another stop/start cycle.
You should already know EC2 launch, SSH and User Data. This fresh environment provides its own image, network, key pair and startup script. You will launch and operate the server yourself.
Certification Relevance
Instance operations and public addressing support compute and networking concepts in Tasks 3.3 and 3.5 of the AWS Certified Cloud Practitioner CLF-C02 Domain 3 objectives.
Launch the Maintenance Server
In this step, you will launch the application server and inspect its initial state and addresses.
Start in the project directory:
cd /home/labex/project
Load the supplied image, subnet and security group IDs:
source launch.env
The supplied startup script configures the report application's greeting. Inspect it before using it:
cat lifecycle-user-data.sh
Look for the message Lifecycle server. As in the preceding lab, --user-data file://... reads the Bash script and supplies it to the instance at launch. Create one server named lifecycle-server:
aws ec2 \
run-instances \
--image-id "$AMI_ID" \
--instance-type t3.micro \
--subnet-id "$SUBNET_ID" \
--security-group-ids "$SECURITY_GROUP_ID" \
--key-name report-key \
--count 1 \
--user-data file://lifecycle-user-data.sh \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=lifecycle-server}]'
Save the instance ID from its name-tag query for the following operations:
INSTANCE_ID=$(aws ec2 \
describe-instances \
--filters Name=tag:Name,Values=lifecycle-server \
--query 'Reservations[0].Instances[0].InstanceId' \
--output text)
Inspect its state and network addresses:
aws ec2 \
describe-instances \
--instance-ids "$INSTANCE_ID" \
--query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name,PrivateIPv4:PrivateIpAddress,PublicIPv4:PublicIpAddress}'
Confirm running; repeat the query after a short wait if it is still pending. Note the private and public IPv4 addresses in the output. You will compare them after maintenance.
Open AWS View and click Refresh resources. Select lifecycle-server under Application requests, then click Check application. Confirm HTTP 200 and Lifecycle server before changing the instance state.
Stop the Server for Maintenance
In this step, you will stop the instance and confirm that it cannot serve application requests.
A stopped instance is shut down and can be started again. A terminated instance has been permanently removed. For an EBS-backed instance, stopping preserves its root volume; the instance's application is unavailable while it is stopped. The official instance lifecycle guide explains these state differences.
Stop your application instance:
aws ec2 \
stop-instances \
--instance-ids "$INSTANCE_ID"
Wait for stopped. The waiter polls the state and returns without output when the condition is satisfied:
aws ec2 \
wait instance-stopped \
--instance-ids "$INSTANCE_ID"
Inspect the state and addresses again:
aws ec2 \
describe-instances \
--instance-ids "$INSTANCE_ID" \
--query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name,PrivateIPv4:PrivateIpAddress,PublicIPv4:PublicIpAddress}'
Confirm stopped. The private IPv4 address remains, while the automatically assigned public IPv4 address is released. You will need the current public address after starting it again.
Refresh AWS View. Confirm stopped and that this instance is no longer available in the running application selector. The server is unavailable during maintenance, even though its instance record and root storage remain.
Retain a Public Address with an Elastic IP
In this step, you will start the server, associate an Elastic IP and check that its public endpoint remains associated across another stop/start cycle.
Start the existing instance:
aws ec2 \
start-instances \
--instance-ids "$INSTANCE_ID"
Wait for running:
aws ec2 \
wait instance-running \
--instance-ids "$INSTANCE_ID"
Inspect its addresses:
aws ec2 \
describe-instances \
--instance-ids "$INSTANCE_ID" \
--query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name,PrivateIPv4:PrivateIpAddress,PublicIPv4:PublicIpAddress}'
The instance ID and private IPv4 address remain the same. The automatically assigned public address changes after stop/start. Refresh AWS View and check the application again; it should still return Lifecycle server.
An Elastic IP is a public IPv4 address allocated to your account until you release it. Allocation reserves the address; association connects it to an instance or network interface. It can provide a stable address across stop/start, as described in the official Elastic IP guide.
Allocate one Elastic IP for VPC use and capture its allocation ID:
ALLOCATION_ID=$(aws ec2 \
allocate-address \
--domain vpc \
--query 'AllocationId' \
--output text)
Associate that allocation with your instance. Save the returned association ID for cleanup:
ASSOCIATION_ID=$(aws ec2 \
associate-address \
--allocation-id "$ALLOCATION_ID" \
--instance-id "$INSTANCE_ID" \
--query 'AssociationId' \
--output text)
Inspect the address and its associated instance:
aws ec2 \
describe-addresses \
--allocation-ids "$ALLOCATION_ID" \
--query 'Addresses[].{PublicIPv4:PublicIp,Allocation:AllocationId,Instance:InstanceId}'
Note the Elastic IP. It replaces the instance's automatically assigned public IPv4 address. Refresh AWS View and check the application to confirm that the new address reaches the same server.
Now perform another maintenance cycle:
aws ec2 \
stop-instances \
--instance-ids "$INSTANCE_ID"
aws ec2 \
wait instance-stopped \
--instance-ids "$INSTANCE_ID"
aws ec2 \
start-instances \
--instance-ids "$INSTANCE_ID"
aws ec2 \
wait instance-running \
--instance-ids "$INSTANCE_ID"
Inspect the instance once more:
aws ec2 \
describe-instances \
--instance-ids "$INSTANCE_ID" \
--query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name,PrivateIPv4:PrivateIpAddress,PublicIPv4:PublicIpAddress}'
Confirm the public address is still the Elastic IP you noted. Refresh AWS View and click Check application. HTTP 200 with Lifecycle server confirms that the server is serving requests through the retained address after maintenance.
Release the Address and Terminate the Server
In this step, you will release the allocated address and permanently remove the application instance.
Disassociation removes the connection to the instance. It does not release the address from your account. First disassociate your saved association:
aws ec2 \
disassociate-address \
--association-id "$ASSOCIATION_ID"
Then release the allocation:
aws ec2 \
release-address \
--allocation-id "$ALLOCATION_ID"
Allocated public IPv4 addresses remain billable resources in AWS, including when an instance is stopped. Releasing an address you no longer need is part of resource cleanup.
Terminate the server:
aws ec2 \
terminate-instances \
--instance-ids "$INSTANCE_ID"
Wait for termination:
aws ec2 \
wait instance-terminated \
--instance-ids "$INSTANCE_ID"
Inspect the final instance state:
aws ec2 \
describe-instances \
--instance-ids "$INSTANCE_ID" \
--query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name}'
Confirm terminated. List the remaining Elastic IP allocations:
aws ec2 \
describe-addresses \
--query 'Addresses[].{Allocation:AllocationId,PublicIPv4:PublicIp}'
The result should be an empty list, []. Refresh AWS View and confirm the server is no longer a running target. Leave the prepared network and key pair in place.
Summary
You stopped and started an EC2 application server, observed address changes and associated an Elastic IP. You verified application access through the retained address after another maintenance cycle. Finally, you released the allocation and terminated the server, confirming that both resources were cleaned up.



