DEV Community

Creating a Custom Amazon Machine Image (AMI) with HashiCorp Packer on AWS

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"
  }

}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Step 3: Build the AMI

Initialize and run Packer:

packer init .
packer fmt .
packer validate webserver.pkr.hcl
packer build webserver.pkr.hcl
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

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

DevCycle image

Ship Faster, Stay Flexible.

DevCycle is the first feature flag platform with OpenFeature built-in to every open source SDK, designed to help developers ship faster while avoiding vendor-lock in.

Start shipping

Top comments (0)

Best Practices for Running  Container WordPress on AWS (ECS, EFS, RDS, ELB) using CDK cover image

Best Practices for Running Container WordPress on AWS (ECS, EFS, RDS, ELB) using CDK

This post discusses the process of migrating a growing WordPress eShop business to AWS using AWS CDK for an easily scalable, high availability architecture. The detailed structure encompasses several pillars: Compute, Storage, Database, Cache, CDN, DNS, Security, and Backup.

Read full post

👋 Kindness is contagious

Take a moment to explore this thoughtful article, beloved by the supportive DEV Community. Coders of every background are invited to share and elevate our collective know-how.

A heartfelt "thank you" can brighten someone's day—leave your appreciation below!

On DEV, sharing knowledge smooths our journey and tightens our community bonds. Enjoyed this? A quick thank you to the author is hugely appreciated.

Okay