In this blog post, we’ll walk through the process of creating a custom Amazon Machine Image (AMI) using HashiCorp Packer. By the end of this guide, you'll understand how to automate AMI creation, customize it with application packages (like Apache HTTP server), and deploy EC2 instances using your new AMI.
What is Packer?
Packer is an open-source tool developed by HashiCorp that allows you to create identical machine images for multiple platforms from a single source configuration. In the context of AWS, Packer automates the creation of Amazon Machine Images (AMIs) using a simple JSON or HCL (HashiCorp Configuration Language) template.
Why use Packer?
- Automates image creation.
- Ensures consistent infrastructure environments.
- Integrates well with CI/CD pipelines.
- Reduces manual effort and configuration drift.
Step 1: Create Packer Template to Build Amazon Linux 2024 AMI
Let’s begin by creating a Packer template using HCL2 syntax. Save the following as webserver.pkr.hcl:
locals {
timestamp = regex_replace(timestamp(), "[- TZ:]", "")
}
variable "ami_prefix" {
type = string
default = "packer-linux-aws"
}
packer {
required_plugins {
amazon = {
version = ">= 1.2.8"
source = "github.com/hashicorp/amazon"
}
}
}
source "amazon-ebs" "al2023" {
ami_name = "${var.ami_prefix}-${local.timestamp}"
instance_type = "t2.micro"
region = "us-east-1"
source_ami_filter {
filters = {
name = "al2023-ami-2023.*-x86_64"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["amazon"]
# owners = ["099720109477"]
}
ssh_username = "ec2-user"
}
build {
name = "ami-packer"
sources = [
"source.amazon-ebs.al2023"
]
provisioner "shell" {
scripts = ["install_httpd.sh"]
}
post-processor "manifest" {
output = "ami_manifest.json"
}
}
Step 2: Create Shell Script to Install Apache HTTP Server
Create a file called install_httpd.sh in the same directory:
# Update and install Apache on Ubuntu
sudo yum update -y
sudo yum install -y httpd.x86_64
# Start and enable Apache service
sudo systemctl start httpd.service
sudo systemctl enable httpd.service
# Fetch EC2 instance metadata using IMDSv2
TOKEN=$(curl --request PUT "http://169.254.169.254/latest/api/token" --header "X-aws-ec2-metadata-token-ttl-seconds: 3600")
AMI_ID=$(curl -s http://169.254.169.254/latest/meta-data/ami-id \ --header "X-aws-ec2-metadata-token: $TOKEN")
# Write HTML output to Apache's web root
cat <<EOF | sudo tee /var/www/html/index.html > /dev/null
<font face="Verdana" size="5">
<center><h1>AWS Linux VM from AMI generated by PACKER </h1></center>
<center><b>AMI ID:</b> $AMI_ID</center>
</font>
EOF
Step 3: Build the AMI
Initialize and run Packer:
packer init .
packer fmt .
packer validate webserver.pkr.hcl
packer build webserver.pkr.hcl
Packer Build Output:
F:\AWS\packer-aws-ami-builder>packer build webserver.pkr.hcl
ami-packer.amazon-ebs.al2023: output will be in this color.
==> ami-packer.amazon-ebs.al2023: Prevalidating any provided VPC information
==> ami-packer.amazon-ebs.al2023: Prevalidating AMI Name: packer-linux-aws-20250702143408
==> ami-packer.amazon-ebs.al2023: Found Image ID: ami-05ffe3c48a9991133
==> ami-packer.amazon-ebs.al2023: Creating temporary keypair: packer_68654361-a0f2-5de6-74b0-f12980d6f3e6
==> ami-packer.amazon-ebs.al2023: Creating temporary security group for this instance: packer_68654365-826a-1380-ae5e-91b28981274a
==> ami-packer.amazon-ebs.al2023: Authorizing access to port 22 from [0.0.0.0/0] in the temporary security groups...
==> ami-packer.amazon-ebs.al2023: Launching a source AWS instance...
==> ami-packer.amazon-ebs.al2023: Instance ID: i-0dd7b3c87f1785e55
==> ami-packer.amazon-ebs.al2023: Waiting for instance (i-0dd7b3c87f1785e55) to become ready...
==> ami-packer.amazon-ebs.al2023: Using SSH communicator to connect: 54.90.148.237
==> ami-packer.amazon-ebs.al2023: Waiting for SSH to become available...
==> ami-packer.amazon-ebs.al2023: Connected to SSH!
==> ami-packer.amazon-ebs.al2023: Provisioning with shell script: install_httpd.sh
==> ami-packer.amazon-ebs.al2023: Waiting for process with pid 2216 to finish.
==> ami-packer.amazon-ebs.al2023: Amazon Linux 2023 Kernel Livepatch repository 169 kB/s | 17 kB 00:00
==> ami-packer.amazon-ebs.al2023: Dependencies resolved.
==> ami-packer.amazon-ebs.al2023: Nothing to do.
==> ami-packer.amazon-ebs.al2023: Complete!
==> ami-packer.amazon-ebs.al2023: Last metadata expiration check: 0:00:01 ago on Wed Jul 2 14:35:15 2025.
==> ami-packer.amazon-ebs.al2023: Dependencies resolved.
==> ami-packer.amazon-ebs.al2023: ================================================================================
==> ami-packer.amazon-ebs.al2023: Package Arch Version Repository Size
==> ami-packer.amazon-ebs.al2023: ================================================================================
==> ami-packer.amazon-ebs.al2023: Installing:
==> ami-packer.amazon-ebs.al2023: httpd x86_64 2.4.62-1.amzn2023 amazonlinux 48 k
==> ami-packer.amazon-ebs.al2023: Installing dependencies:
==> ami-packer.amazon-ebs.al2023: apr x86_64 1.7.5-1.amzn2023.0.4 amazonlinux 129 k
==> ami-packer.amazon-ebs.al2023: apr-util x86_64 1.6.3-1.amzn2023.0.1 amazonlinux 98 k
==> ami-packer.amazon-ebs.al2023: generic-logos-httpd noarch 18.0.0-12.amzn2023.0.3 amazonlinux 19 k
==> ami-packer.amazon-ebs.al2023: httpd-core x86_64 2.4.62-1.amzn2023 amazonlinux 1.4 M
==> ami-packer.amazon-ebs.al2023: httpd-filesystem noarch 2.4.62-1.amzn2023 amazonlinux 14 k
==> ami-packer.amazon-ebs.al2023: httpd-tools x86_64 2.4.62-1.amzn2023 amazonlinux 81 k
==> ami-packer.amazon-ebs.al2023: libbrotli x86_64 1.0.9-4.amzn2023.0.2 amazonlinux 315 k
==> ami-packer.amazon-ebs.al2023: mailcap noarch 2.1.49-3.amzn2023.0.3 amazonlinux 33 k
==> ami-packer.amazon-ebs.al2023: Installing weak dependencies:
==> ami-packer.amazon-ebs.al2023: apr-util-openssl x86_64 1.6.3-1.amzn2023.0.1 amazonlinux 17 k
==> ami-packer.amazon-ebs.al2023: mod_http2 x86_64 2.0.27-1.amzn2023.0.3 amazonlinux 166 k
==> ami-packer.amazon-ebs.al2023: mod_lua x86_64 2.4.62-1.amzn2023 amazonlinux 61 k
==> ami-packer.amazon-ebs.al2023:
==> ami-packer.amazon-ebs.al2023: Transaction Summary
==> ami-packer.amazon-ebs.al2023: ================================================================================
==> ami-packer.amazon-ebs.al2023: Install 12 Packages
==> ami-packer.amazon-ebs.al2023:
==> ami-packer.amazon-ebs.al2023: Total download size: 2.3 M
==> ami-packer.amazon-ebs.al2023: Installed size: 6.9 M
==> ami-packer.amazon-ebs.al2023: Downloading Packages:
==> ami-packer.amazon-ebs.al2023: (1/12): apr-util-openssl-1.6.3-1.amzn2023.0.1.x 404 kB/s | 17 kB 00:00
==> ami-packer.amazon-ebs.al2023: (2/12): apr-1.7.5-1.amzn2023.0.4.x86_64.rpm 2.7 MB/s | 129 kB 00:00
==> ami-packer.amazon-ebs.al2023: (3/12): apr-util-1.6.3-1.amzn2023.0.1.x86_64.rp 1.9 MB/s | 98 kB 00:00
==> ami-packer.amazon-ebs.al2023: (4/12): generic-logos-httpd-18.0.0-12.amzn2023. 891 kB/s | 19 kB 00:00
==> ami-packer.amazon-ebs.al2023: (5/12): httpd-2.4.62-1.amzn2023.x86_64.rpm 2.1 MB/s | 48 kB 00:00
==> ami-packer.amazon-ebs.al2023: (6/12): httpd-filesystem-2.4.62-1.amzn2023.noar 639 kB/s | 14 kB 00:00
==> ami-packer.amazon-ebs.al2023: (7/12): httpd-core-2.4.62-1.amzn2023.x86_64.rpm 31 MB/s | 1.4 MB 00:00
==> ami-packer.amazon-ebs.al2023: (8/12): httpd-tools-2.4.62-1.amzn2023.x86_64.rp 2.7 MB/s | 81 kB 00:00
==> ami-packer.amazon-ebs.al2023: (9/12): libbrotli-1.0.9-4.amzn2023.0.2.x86_64.r 9.9 MB/s | 315 kB 00:00
==> ami-packer.amazon-ebs.al2023: (10/12): mailcap-2.1.49-3.amzn2023.0.3.noarch.r 1.4 MB/s | 33 kB 00:00
==> ami-packer.amazon-ebs.al2023: (11/12): mod_http2-2.0.27-1.amzn2023.0.3.x86_64 4.8 MB/s | 166 kB 00:00
==> ami-packer.amazon-ebs.al2023: (12/12): mod_lua-2.4.62-1.amzn2023.x86_64.rpm 2.3 MB/s | 61 kB 00:00
==> ami-packer.amazon-ebs.al2023: --------------------------------------------------------------------------------
==> ami-packer.amazon-ebs.al2023: Total 13 MB/s | 2.3 MB 00:00
==> ami-packer.amazon-ebs.al2023: Running transaction check
==> ami-packer.amazon-ebs.al2023: Transaction check succeeded.
==> ami-packer.amazon-ebs.al2023: Running transaction test
==> ami-packer.amazon-ebs.al2023: Transaction test succeeded.
==> ami-packer.amazon-ebs.al2023: Running transaction
==> ami-packer.amazon-ebs.al2023: Preparing : 1/1
==> ami-packer.amazon-ebs.al2023: Installing : apr-1.7.5-1.amzn2023.0.4.x86_64 1/12
==> ami-packer.amazon-ebs.al2023: Installing : apr-util-openssl-1.6.3-1.amzn2023.0.1.x86_64 2/12
==> ami-packer.amazon-ebs.al2023: Installing : apr-util-1.6.3-1.amzn2023.0.1.x86_64 3/12
==> ami-packer.amazon-ebs.al2023: Installing : mailcap-2.1.49-3.amzn2023.0.3.noarch 4/12
==> ami-packer.amazon-ebs.al2023: Installing : httpd-tools-2.4.62-1.amzn2023.x86_64 5/12
==> ami-packer.amazon-ebs.al2023: Installing : libbrotli-1.0.9-4.amzn2023.0.2.x86_64 6/12
==> ami-packer.amazon-ebs.al2023: Running scriptlet: httpd-filesystem-2.4.62-1.amzn2023.noarch 7/12
==> ami-packer.amazon-ebs.al2023: Installing : httpd-filesystem-2.4.62-1.amzn2023.noarch 7/12
==> ami-packer.amazon-ebs.al2023: Installing : httpd-core-2.4.62-1.amzn2023.x86_64 8/12
==> ami-packer.amazon-ebs.al2023: Installing : mod_http2-2.0.27-1.amzn2023.0.3.x86_64 9/12
==> ami-packer.amazon-ebs.al2023: Installing : mod_lua-2.4.62-1.amzn2023.x86_64 10/12
==> ami-packer.amazon-ebs.al2023: Installing : generic-logos-httpd-18.0.0-12.amzn2023.0.3.noarch 11/12
==> ami-packer.amazon-ebs.al2023: Installing : httpd-2.4.62-1.amzn2023.x86_64 12/12
==> ami-packer.amazon-ebs.al2023: Running scriptlet: httpd-2.4.62-1.amzn2023.x86_64 12/12
==> ami-packer.amazon-ebs.al2023: Verifying : apr-1.7.5-1.amzn2023.0.4.x86_64 1/12
==> ami-packer.amazon-ebs.al2023: Verifying : apr-util-1.6.3-1.amzn2023.0.1.x86_64 2/12
==> ami-packer.amazon-ebs.al2023: Verifying : apr-util-openssl-1.6.3-1.amzn2023.0.1.x86_64 3/12
==> ami-packer.amazon-ebs.al2023: Verifying : generic-logos-httpd-18.0.0-12.amzn2023.0.3.noarch 4/12
==> ami-packer.amazon-ebs.al2023: Verifying : httpd-2.4.62-1.amzn2023.x86_64 5/12
==> ami-packer.amazon-ebs.al2023: Verifying : httpd-core-2.4.62-1.amzn2023.x86_64 6/12
==> ami-packer.amazon-ebs.al2023: Verifying : httpd-filesystem-2.4.62-1.amzn2023.noarch 7/12
==> ami-packer.amazon-ebs.al2023: Verifying : httpd-tools-2.4.62-1.amzn2023.x86_64 8/12
==> ami-packer.amazon-ebs.al2023: Verifying : libbrotli-1.0.9-4.amzn2023.0.2.x86_64 9/12
==> ami-packer.amazon-ebs.al2023: Verifying : mailcap-2.1.49-3.amzn2023.0.3.noarch 10/12
==> ami-packer.amazon-ebs.al2023: Verifying : mod_http2-2.0.27-1.amzn2023.0.3.x86_64 11/12
==> ami-packer.amazon-ebs.al2023: Verifying : mod_lua-2.4.62-1.amzn2023.x86_64 12/12
==> ami-packer.amazon-ebs.al2023:
==> ami-packer.amazon-ebs.al2023: Installed:
==> ami-packer.amazon-ebs.al2023: apr-1.7.5-1.amzn2023.0.4.x86_64
==> ami-packer.amazon-ebs.al2023: apr-util-1.6.3-1.amzn2023.0.1.x86_64
==> ami-packer.amazon-ebs.al2023: apr-util-openssl-1.6.3-1.amzn2023.0.1.x86_64
==> ami-packer.amazon-ebs.al2023: generic-logos-httpd-18.0.0-12.amzn2023.0.3.noarch
==> ami-packer.amazon-ebs.al2023: httpd-2.4.62-1.amzn2023.x86_64
==> ami-packer.amazon-ebs.al2023: httpd-core-2.4.62-1.amzn2023.x86_64
==> ami-packer.amazon-ebs.al2023: httpd-filesystem-2.4.62-1.amzn2023.noarch
==> ami-packer.amazon-ebs.al2023: httpd-tools-2.4.62-1.amzn2023.x86_64
==> ami-packer.amazon-ebs.al2023: libbrotli-1.0.9-4.amzn2023.0.2.x86_64
==> ami-packer.amazon-ebs.al2023: mailcap-2.1.49-3.amzn2023.0.3.noarch
==> ami-packer.amazon-ebs.al2023: mod_http2-2.0.27-1.amzn2023.0.3.x86_64
==> ami-packer.amazon-ebs.al2023: mod_lua-2.4.62-1.amzn2023.x86_64
==> ami-packer.amazon-ebs.al2023:
==> ami-packer.amazon-ebs.al2023: Complete!
==> ami-packer.amazon-ebs.al2023: Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
==> ami-packer.amazon-ebs.al2023: % Total % Received % Xferd Average Speed Time Time Time Current
==> ami-packer.amazon-ebs.al2023: Dload Upload Total Spent Left Speed
==> ami-packer.amazon-ebs.al2023: 100 56 100 56 0 0 3558 0 --:--:-- --:--:-- --:--:-- 3733
==> ami-packer.amazon-ebs.al2023: Stopping the source instance...
==> ami-packer.amazon-ebs.al2023: Stopping instance
==> ami-packer.amazon-ebs.al2023: Waiting for the instance to stop...
==> ami-packer.amazon-ebs.al2023: Creating AMI packer-linux-aws-20250702143408 from instance i-0dd7b3c87f1785e55
==> ami-packer.amazon-ebs.al2023: Attaching run tags to AMI...
==> ami-packer.amazon-ebs.al2023: AMI: ami-07fd4efba2459fded
==> ami-packer.amazon-ebs.al2023: Waiting for AMI to become ready...
==> ami-packer.amazon-ebs.al2023: Skipping Enable AMI deprecation...
==> ami-packer.amazon-ebs.al2023: Skipping Enable AMI deregistration protection...
==> ami-packer.amazon-ebs.al2023: Terminating the source AWS instance...
==> ami-packer.amazon-ebs.al2023: Cleaning up any extra volumes...
==> ami-packer.amazon-ebs.al2023: No volumes to clean up, skipping
==> ami-packer.amazon-ebs.al2023: Deleting temporary security group...
==> ami-packer.amazon-ebs.al2023: Deleting temporary keypair...
==> ami-packer.amazon-ebs.al2023: Running post-processor: (type manifest)
Build 'ami-packer.amazon-ebs.al2023' finished after 4 minutes 2 seconds.
==> Wait completed after 4 minutes 2 seconds
==> Builds finished. The artifacts of successful builds are:
--> ami-packer.amazon-ebs.al2023: AMIs were created:
us-east-1: ami-07fd4efba2459fded
--> ami-packer.amazon-ebs.al2023: AMIs were created:
us-east-1: ami-07fd4efba2459fded
Step 4: Launch EC2 Instance with Custom AMI
Now, launch an EC2 instance using the new AMI either from the AWS Console or via the AWS CLI.
{
"builds": [
{
"name": "al2023",
"builder_type": "amazon-ebs",
"build_time": 1751467092,
"files": null,
"artifact_id": "us-east-1:ami-07fd4efba2459fded",
"packer_run_uuid": "34de68b8-912a-db78-dda3-7e9adc74103b",
"custom_data": null
}
],
"last_run_uuid": "34de68b8-912a-db78-dda3-7e9adc74103b"
}
Cleanup
Don’t forget to clean up your resources to avoid unnecessary AWS charges:
Terminate any EC2 instances you launched.
Deregister the AMI if no longer needed:
Delete associated snapshots from the EC2 → Snapshots section in the console.
Conclusion
Using Packer to automate the creation of AMIs is a powerful DevOps practice. It simplifies provisioning, ensures consistency, and accelerates deployments. With just a few lines of configuration and scripts, you can embed software installations, configurations, and more into machine images.
Whether you’re deploying single EC2 instances or autoscaling groups, pre-baked AMIs help you scale with confidence and speed.
References
Github Repo: https://github.com/chinmayto/packer-aws-ami-builder
Top comments (0)