

# Using a custom Amazon machine image (AMI) in your Elastic Beanstalk environment
<a name="using-features.customenv"></a>

This section explains when to consider using a custom AMI and provides the procedures to configure and manage the custom AMI in your environment. When you create an AWS Elastic Beanstalk environment, you can specify an Amazon Machine Image (AMI) to use instead of the standard Elastic Beanstalk AMI included in your platform version. A custom AMI can improve provisioning times when instances are launched in your environment if you need to install a lot of software that isn't included in the standard AMIs.

The use of [configuration files](ebextensions.md) is effective to customize your environment quickly and consistently. Although applying configurations can start to take a long time during environment creation and updates. If you do a lot of server configuration in configuration files, you can reduce this time by making a custom AMI that already has the software and configuration that you need.

A custom AMI also allows you to make changes to low-level components, such as the Linux kernel, that are difficult to implement or take a long time to apply in configuration files. To create a custom AMI, launch an Elastic Beanstalk platform AMI in Amazon EC2, customize the software and configuration to your needs, and then stop the instance and save an AMI from it.

## Creating a custom AMI
<a name="using-features.customenv.create"></a>

You can use [EC2 Image Builder](https://aws.amazon.com/image-builder) to create and manage custom AMIs as an alternative to these procedures. For more information, see the [Image Builder User Guide](https://docs.aws.amazon.com/imagebuilder/latest/userguide/what-is-image-builder.html).

**To identify the base Elastic Beanstalk AMI**

1. In a command window, run a command like the following. For more information, see [describe-platform-version](https://docs.aws.amazon.com/cli/latest/reference/elasticbeanstalk/describe-platform-version.html) in the *AWS CLI Command Reference*. 

   Specify the AWS Region where you want to use your custom AMI, and replace the platform ARN and version number with the Elastic Beanstalk platform that your application is based on.

     
**Example - Mac OS / Linux OS**  

   ```
   $ aws elasticbeanstalk describe-platform-version --region us-east-2 \
         --platform-arn "arn:aws:elasticbeanstalk:us-east-2::platform/Node.js 20 running on 64bit Amazon Linux 2023/6.1.7" \
         --query PlatformDescription.CustomAmiList
   [
       {
           "VirtualizationType": "pv",
           "ImageId": ""
       },
       {
           "VirtualizationType": "hvm",
           "ImageId": "ami-020ae06fdda6a0f66"
       }
   ]
   ```  
**Example - Windows OS**  

   ```
   C:\> aws elasticbeanstalk describe-platform-version --region us-east-2 --platform-arn"arn:aws:elasticbeanstalk:us-east-2::platform/
   IIS 10.0 running on 64bit Windows Server 2022/2.15.3" --query PlatformDescription.CustomAmiList
   [
       {
           "VirtualizationType": "pv",
           "ImageId": ""
       },
       {
           "VirtualizationType": "hvm",
           "ImageId": "ami-020ae06fdda6a0f66"
       }
   ]
   ```

1. Take note of the `ImageId` value that looks like `ami-020ae06fdda6a0f66` in the result.

The value is the stock Elastic Beanstalk AMI for the platform version, EC2 instance architecture, and AWS Region that are relevant for your application. If you need to create AMIs for multiple platforms, architectures or AWS Regions, repeat this process to identify the correct base AMI for each combination.

**Note**  
Don't create an AMI from an instance that has been launched in an Elastic Beanstalk environment. Elastic Beanstalk makes changes to instances during provisioning that can cause issues in the saved AMI. Saving an image from an instance in an Elastic Beanstalk environment will also make the version of your application that was deployed to the instance a fixed part of the image.

For Linux, it is also possible to create a custom AMI from a community AMI that wasn't published by Elastic Beanstalk. You can use the latest [Amazon Linux](https://aws.amazon.com/amazon-linux-ami/) AMI as a starting point. When you launch an environment with a Linux AMI that isn't managed by Elastic Beanstalk, Elastic Beanstalk attempts to install platform software (language, framework, proxy server, etc.) and additional components to support features such as [Enhanced Health Reporting](health-enhanced.md). 

**Note**  
Custom AMIs based on Windows Server require the stock Elastic Beanstalk AMI returned from `describe-platform-version`, as shown earlier in Step 1.

Although Elastic Beanstalk can use an AMI that isn't managed by Elastic Beanstalk, the increase in provisioning time that results from Elastic Beanstalk installing missing components can reduce or eliminate the benefits of creating a custom AMI in the first place. Other Linux distributions might work with some troubleshooting but are not officially supported. If your application requires a specific Linux distribution, one alternative is to create a Docker image and run it on the Elastic Beanstalk [Docker platform](docker.md) or [Multicontainer Docker platform](create_deploy_docker_ecs.md).

**To create a custom AMI**

1. Open the Amazon EC2 console at [https://console.aws.amazon.com/ec2/](https://console.aws.amazon.com/ec2/).

1. Choose **Launch Instance**.

1. If you identified a base Elastic Beanstalk AMI (using `describe-platform-version`) or an Amazon Linux AMI, enter its AMI ID in the search box. Then press **Enter**.

   You can also search the list for another community AMI that suits your needs.
**Note**  
We recommend that you choose an AMI that uses HVM virtualization. These AMIs show **Virtualization type: hvm** in their description.  
For more information, see [Virtualization types](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ComponentsAMIs.html#virtualization_types) in the *Amazon EC2 User Guide*.

1. Choose **Select** to select the AMI.

1. Select an instance type, and then choose **Next: Configure Instance Details**.

1. **(For retired Amazon Linux AMI (AL1) platforms)** Skip this step if your environment runs on a supported Linux-based platform or on a Windows platform.

   Expand the **Advanced Details** section and paste the following text in the **User Data** field.

   ```
   #cloud-config
     repo_releasever: repository version number
     repo_upgrade: none
   ```

   The *repository version number* is the year and month version in the AMI name. For example, AMIs based on the March 2015 release of Amazon Linux have a repository version number `2015.03`. For an Elastic Beanstalk image, this matches the date shown in the solution stack name for your [platform version](concepts.platforms.md) based on Amazon Linux AMI (preceding Amazon Linux 2).
**Note**  
The `repo_releasever` setting configures the lock-on-launch feature for an Amazon Linux AMI. This causes the AMI to use a fixed, specific repository version when it launches. This feature isn't supported on Amazon Linux 2—don't specify it if your environment uses a current Amazon Linux 2 platform branch. The setting is required if you're using a custom AMI with Elastic Beanstalk only on Amazon Linux AMI platform branches (preceding Amazon Linux 2).  
The `repo_upgrade` setting disables the automatic installation of security updates. It's required to use a custom AMI with Elastic Beanstalk.

1. Proceed through the wizard to [launch the EC2 instance](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/launching-an-instance.html). When prompted, select a key pair that you have access to so that you can connect to the instance for the next steps.

1.  [Connect to the instance](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstances.html) with SSH or RDP.

1. Perform any customizations you want.

1. **(Windows platforms)** Run the EC2Config service Sysprep. For information about EC2Config, see [Configuring a Windows Instance Using the EC2Config Service](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/UsingConfig_WinAMI.html). Ensure that Sysprep is configured to generate a random password that can be retrieved from the AWS Management Console.

1. In the Amazon EC2 console, stop the EC2 instance. Then on the **Instance Actions** menu, choose **Create Image (EBS AMI)**.

1. To avoid incurring additional AWS charges, [terminate the EC2 instance](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html).

**To use your custom AMI in an Elastic Beanstalk environment**

1. Open the [Elastic Beanstalk console](https://console.aws.amazon.com/elasticbeanstalk), and in the **Regions** list, select your AWS Region.

1. In the navigation pane, choose **Environments**, and then choose the name of your environment from the list.

1. In the navigation pane, choose **Configuration**.

1. In the **Capacity** configuration category, choose **Edit**.

1. For **AMI ID**, enter your custom AMI ID.

1. To save the changes choose **Apply** at the bottom of the page.

When you create a new environment with the custom AMI, you should use the same platform version that you used as a base to create the AMI. 

## Managing an environment with a custom AMI
<a name="using-features.customenv.managing"></a>

### Platform updates
<a name="using-features.customenv.platform-updates."></a>

When using a custom AMI, Elastic Beanstalk will continue to use the same custom AMI in an environment when its platform version is updated, regardless of whether the update is applied manually or via managed platform updates. The environment will **not** be reset to use the stock AMI of the new platform version.

We recommend that you create a new custom AMI based on the stock AMI of the new platform version. Doing so will apply the patches available in the new platform version and will also minimize deployment failures due to incompatible package or library versions.

For more information about creating a new custom AMI, see the [Creating a custom AMI](#using-features.customenv.create) earlier in this topic.

### Removing a custom AMI
<a name="using-features.customenv.platform-updates."></a>

If you would like to remove a custom AMI from an environment and reset it to use the stock AMI for the environment’s platform version, use the following CLI command.

```
aws elasticbeanstalk update-environment \
  --application-name my-application \
  --environment-name my-environment \
  --region us-east-1 \
  --options-to-remove Namespace=aws:autoscaling:launchconfiguration,OptionName=ImageId
```

**Note**  
To avoid disruption of your service, test your application with a stock AMI before applying this change to your production environment.

## Cleaning up a custom AMI
<a name="using-features.customenv.cleanup"></a>

When you are done with a custom AMI and don't need it to launch Elastic Beanstalk environments anymore, consider cleaning it up to minimize storage cost. Cleaning up a custom AMI involves deregistering it from Amazon EC2 and deleting other associated resources. For details, see [Deregistering Your Linux AMI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/deregister-ami.html) or [Deregistering Your Windows AMI](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/deregister-ami.html).

# Preserving access to an Amazon Machine Image (AMI) for a retired platform
<a name="using-features.customenv-env-copy"></a>

Elastic Beanstalk sets a platform branch status to *retired* when the operating system or major component used by the branch reaches End of Life. The *base *Elastic Beanstalk AMI for the platform branch may also be made private to prevent the use of this out-of-date AMI. Environments using AMIs that have been made private will no longer be able to launch instances.

If you're unable to migrate your application to a supported environment before it's retired, your environment may be in this situation. The need to update an environment for a Beanstalk platform branch, where its base Elastic Beanstalk AMI has been made private, may arise. An alternative approach is available. You can update an existing environment based on a *copy* of the base Elastic Beanstalk AMI used by your environment. 

This topic offers some steps and a standalone script to update an existing environment based on a *copy* of the base Elastic Beanstalk AMI used by your environment. Once you're able to migrate your application to a supported platform you can continue to use the standard procedures for maintaining your application and supported environments.

## Manual steps
<a name="using-features.customenv-env-copy.manual-steps"></a>

**To update an environment based on an AMI copy of the base Elastic Beanstalk AMI**

1. **Determine which AMI your environment is using.** This command returns the AMI used by the Elastic Beanstalk environment that you provide in the parameters. The returned value is used as the *source-ami-id* in the next step.

   In a command window, run a command like the following. For more information, see [describe-configuration-settings](https://docs.aws.amazon.com/cli/latest/reference/elasticbeanstalk/describe-configuration-settings.html) in the *AWS CLI Command Reference*.

   Specify the AWS Region that stores the source AMI you want to copy. Replace the application name and environment name with those based on the source AMI. Enter the text for the query parameter as shown.  
**Example**  

   ```
   >aws elasticbeanstalk describe-configuration-settings \
     --application-name my-application \
     --environment-name my-environment \
     --region us-east-2 \
     --query "ConfigurationSettings[0].OptionSettings[?OptionName=='ImageId'] | [0].Value"
   ```

1. **Copy the AMI into your account.** This command returns the new AMI that results from copying the *source-ami-id* that was returned in the prior step. 
**Note**  
Be sure to make a note of the new AMI id that is output by this command. You'll need to enter it in the next step, replacing *copied-ami-id* in the example command.

   In a command window, run a command like the following. For more information, see [copy-image](https://docs.aws.amazon.com/cli/latest/reference/ec2/copy-image.html) in the *AWS CLI Command Reference*.

   Specify the AWS Region of the source AMI you want to copy (**--source-region**) and the Region where you want to use your new custom AMI (**--region**). Replace *source-ami-id *with the AMI of the image that you're copying. The *source-ami-id* was returned by the command in the prior step. Replace *new-ami-name* with a name to describe the new AMI in the destination Region. The script that follows this procedure generates the new AMI name by appending the string "*Copy of*" to the beginning of the name of the *source-ami-id.*

   ```
   >aws ec2 copy-image \
       --region us-east-2 \
       --source-image-id source-ami-id \
       --source-region us-east-2 \
       --name new-ami-name
   ```

1. **Update an environment to use the copied AMI.** After the command runs it returns the status of the environment.

   In a command window, run a command like the following. For more information, see [update-environment](https://docs.aws.amazon.com/cli/latest/reference/elasticbeanstalk/update-environment.html) in the *AWS CLI Command Reference*.

   Specify the AWS Region of the environment and application you need to update. Replace the application name and environment name with those you need to associate with the *copied-ami-id* from the prior step. For the **--option-setttings** parameter, replace *copied-ami-id* with the AMI id you noted from the output of the prior command.

   ```
   >aws elasticbeanstalk update-environment \
     --application-name my-application \
     --environment-name my-environment \
     --region us-east-2 \
     --option-settings "Namespace=aws:autoscaling:launchconfiguration,OptionName=ImageId,Value=copied-ami-id"
   ```

**Note**  
To minimize storage costs, consider cleaning up your custom AMI when you don't need it to launch Elastic Beanstalk environments anymore. For more information, see [Cleaning up a custom AMI](using-features.customenv.md#using-features.customenv.cleanup).

## Standalone script
<a name="using-features.customenv-env-copy.script"></a>

The following script provides the same results as the previous manual steps. Download the script by selecting this link: [copy\$1ami\$1and\$1update\$1env.zip](samples/copy_ami_and_update_env.zip).

### Script source: copy\$1ami\$1and\$1update\$1env.sh
<a name="abc"></a>

```
#!/bin/bash

set -ue

USAGE="This script is used to copy an AMI used by your Elastic Beanstalk environment into your account to use in your environment.\n\n" 
USAGE+="Usage:\n\n"
USAGE+="./$(basename $0) [OPTIONS]\n"
USAGE+="OPTIONS:\n"
USAGE+="\t--application-name <application-name>\tThe name of your Elastic Beanstalk application.\n"
USAGE+="\t--environment-name <environment-name>\tThe name of your Elastic Beanstalk environment.\n"
USAGE+="\t--region <region> \t\t\tThe AWS region your Elastic Beanstalk environment is deployed to.\n"
USAGE+="\n\n"
USAGE+="Script Usage Example(s):\n"
USAGE+="./$(basename $0) --application-name my-application --environment-name my-environment --region us-east-1\n"

if [ $# -eq 0 ]; then
  echo -e $USAGE
  exit
fi

while [[ $# -gt 0 ]]; do
  case $1 in
    --application-name)       APPLICATION_NAME="$2"; shift ;;
    --environment-name)       ENVIRONMENT_NAME="$2"; shift ;;
    --region)                 REGION="$2"; shift ;;
    *)                        echo "Unknown option $1" ; echo -e $USAGE ; exit ;;
  esac
  shift
done

aws_cli_version="$(aws --version)"
if [ $? -ne 0 ]; then
  echo "aws CLI not found. Please install it: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html. Exiting."
  exit 1
fi
echo "Using aws CLI version: ${aws_cli_version}"

account=$(aws sts get-caller-identity --query "Account" --output text)
echo "Using account ${account}"

environment_ami_id=$(aws elasticbeanstalk describe-configuration-settings \
  --application-name "$APPLICATION_NAME" \
  --environment-name "$ENVIRONMENT_NAME" \
  --region "$REGION" \
  --query "ConfigurationSettings[0].OptionSettings[?OptionName=='ImageId'] | [0].Value" \
  --output text)
echo "Image associated with environment ${ENVIRONMENT_NAME} is ${environment_ami_id}"

owned_image=$(aws ec2 describe-images \
  --owners self \
  --image-ids "$environment_ami_id" \
  --region "$REGION" \
  --query "Images[0]" \
  --output text)
if [ "$owned_image" != "None" ]; then
  echo "${environment_ami_id} is already owned by account ${account}. Exiting."
  exit
fi

source_image_name=$(aws ec2 describe-images \
  --image-ids "$environment_ami_id" \
  --region "$REGION" \
  --query "Images[0].Name" \
  --output text)
if [ "$source_image_name" = "None" ]; then
  echo "Cannot find ${environment_ami_id}. Please contact AWS support if you need additional help: https://aws.amazon.com/support."
  exit 1
fi

copied_image_name="Copy of ${source_image_name}"
copied_ami_id=$(aws ec2 describe-images \
  --owners self \
  --filters Name=name,Values="${copied_image_name}" \
  --region "$REGION" \
  --query "Images[0].ImageId" \
  --output text)
if [ "$copied_ami_id" != "None" ]; then
  echo "Detected that ${environment_ami_id} has already been copied by account ${account}. Skipping image copy."
else
  echo "Copying ${environment_ami_id} to account ${account} with name ${copied_image_name}"
  copied_ami_id=$(aws ec2 copy-image \
    --source-image-id "$environment_ami_id" \
    --source-region "$REGION" \
    --name "$copied_image_name" \
    --region "$REGION" \
    --query "ImageId" \
    --output text)
  echo "New AMI ID is ${copied_ami_id}"

  echo "Waiting for ${copied_ami_id} to become available"
  aws ec2 wait image-available \
    --image-ids "$copied_ami_id" \
    --region "$REGION"
  echo "${copied_ami_id} is now available"
fi

echo "Updating environment ${ENVIRONMENT_NAME} to use ${copied_ami_id}"
environment_status=$(aws elasticbeanstalk update-environment \
  --application-name "$APPLICATION_NAME" \
  --environment-name "$ENVIRONMENT_NAME" \
  --option-settings "Namespace=aws:autoscaling:launchconfiguration,OptionName=ImageId,Value=${copied_ami_id}" \
  --region "$REGION" \
  --query "Status" \
  --output text)
echo "Environment ${ENVIRONMENT_NAME} is now ${environment_status}"

echo "Waiting for environment ${ENVIRONMENT_NAME} update to complete"
aws elasticbeanstalk wait environment-updated \
  --application-name "$APPLICATION_NAME" \
  --environment-names "$ENVIRONMENT_NAME" \
  --region "$REGION"
echo "Environment ${ENVIRONMENT_NAME} update complete"
```

**Note**  
You must have the AWS CLI installed to execute the script. For installation instructions, see [Install or update the latest version of the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) in the *AWS Command Line Interface User Guide*.  
After installing the AWS CLI, you must also configure it to use the AWS account that owns the environment. For more information, see [Configure the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html) in the *AWS Command Line Interface User Guide*. The account must also have permissions to create an AMI and update the Elastic Beanstalk environment. 

 These steps describe the process that the script follows. 

1. Print the account in use. 

1. Determine which AMI is used by the environment (source AMI).

1. Check if the source AMI is already owned by the account. If yes, exit. 

1. Determine the name of the source AMI so it can be used in the new AMI name. This also serves to confirm access to the source AMI.

1. Check if the source AMI has already been copied to the account. This is done by searching for AMIs with the name of the copied AMI owned by the account. If the AMI name has been changed in between script executions, it will copy the image again.

1. If the source AMI has not already been copied, copy the source AMI to the account and wait for the new AMI to be available.

1. Update the environment configuration to use the new AMI.

1. Wait for the environment update to complete.

After you extract the script from the [copy\$1ami\$1and\$1update\$1env.zip](samples/copy_ami_and_update_env.zip) file, run it by executing the following example. Replace the application name and environment name in the example with your own values.

```
>sh copy_ami_and_update_env.sh \
  --application-name my-application \
  --environment-name my-environment \
  --region us-east-1
```

**Note**  
To minimize storage costs, consider cleaning up your custom AMI when you don't need it to launch Elastic Beanstalk environments anymore. For more information, see [Cleaning up a custom AMI](using-features.customenv.md#using-features.customenv.cleanup).