Amazon Elastic Compute Cloud (Amazon EC2) application status checks monitor application health and responsiveness alongside instance, system, and Amazon Elastic Block Store (Amazon EBS) status checks. You can use them to identify a web server that has stopped accepting requests, a Docker daemon that is not running, an incorrect networking configuration, or a network interface that is no longer passing traffic. Amazon EC2 reports application, instance, system, and Amazon EBS status checks through the DescribeInstanceStatus API and Amazon CloudWatch, so you can monitor application health through these EC2 signals rather than publish a custom health metric.

Application status checks can monitor an EC2 instance whether it is launched using RunInstances, Amazon EC2 Fleet, or Amazon EC2 Auto Scaling. For RunInstances and EC2 Fleet, launch the instance with the tag used by the check association. EC2 reports the application status, and you choose how to respond. Amazon EC2 Auto Scaling monitors instance health and can use included application status checks to automate recovery by replacing an instance when its application status is impaired. When Auto Scaling launches a replacement with the app=database tag, the existing tag-based association includes it, so the application status check monitors the new instance without another association call. This walkthrough uses an Auto Scaling group and also covers CloudWatch alarms, staged onboarding, and application maintenance.

For additional details about the feature and pricing, you can refer to the What’s New post and application status checks in the Amazon EC2 User Guide.

Solution overview

Application status checks report through the DescribeInstanceStatus API and Amazon CloudWatch, so you can consume the result in more than one way. You can poll the status from your own tooling, alarm on the CloudWatch metric and run your own remediation, or rely on Amazon EC2 Auto Scaling to replace an instance whose application status is impaired.

In this example, we use the feature with EC2 Auto Scaling groups. Auto Scaling groups help you manage the instance lifecycle across launching, monitoring, and refreshing instances, and they maintain the number of running instances you specify by replacing an instance that fails a health check. For simplicity, we assume the group is a fixed size, with its desired, minimum, and maximum capacity set to the same value, so replacing an instance keeps capacity steady. We assume we have already set up application monitoring for an application running on EC2 instances in an Amazon EC2 Auto Scaling group. Our goal is to replace an impaired application quickly.

The walkthrough adds one application status check across your instances, surfaces the result in CloudWatch, and configures Auto Scaling to replace an instance whose application status is impaired.

You configure the protocol, port, path, accepted response codes, and failure and success thresholds. EC2 evaluates the endpoint every 60 seconds. A matching response code passes. A different response code, a refused or reset connection, or a timeout counts as a failure. The check reports failed after FailureThreshold consecutive failures and passed after SuccessThreshold consecutive successes. Both thresholds default to 2.

The application status of the instance is separate from the result of any single check. It is the aggregation of the checks associated with the instance that have Aggregation set to included. It reports impaired when at least one included check has a failed result. This is the value that appears as ApplicationStatus in describe-instance-status and that Amazon EC2 Auto Scaling acts on. An initialization grace period delays evaluation after launch, so an application that is still starting is not reported impaired before it is ready. You can associate more than one check with an instance, for example a liveness path and a readiness path, and include or exclude each one from the aggregated instance-level status.

Prerequisites

Before you start, you need the following:

  • An application running on EC2 instances in an Auto Scaling group. If you need to create a group for this walkthrough, see Create an Auto Scaling group using a launch template. Configure the Amazon Machine Image (AMI) or user data in the launch template to install and start the application on each instance.
  • A tag on those instances that you can target, for example app=database.
  • Instances reachable on the health check port from within your virtual private cloud (VPC). With AWS-managed network paths, EC2 matches the health check source to the subnet and security group combinations used by the associated instances. Before creating the check, add an inbound rule to each instance security group that allows health check traffic on the check port from the same security group. The host firewall must also allow the port. The instances do not need public IP addresses.
  • An AWS Identity and Access Management (IAM) principal with permissions for the EC2 application status check actions and EC2 Auto Scaling.
  • Make sure your AWS Command Line Interface (AWS CLI) is up to date. Older releases might not include the application status check commands. If the CLI does not recognize create-application-status-check, follow Installing or updating to the latest version of the AWS CLI before continuing.

If you do not have an application on a health path yet, add a lightweight endpoint that returns a success code when the instance is ready (most web frameworks expose one), or point the check at an existing readiness path. You need at least one running instance in the Auto Scaling group that is reachable on the check port and serving that endpoint to see a passing result.

To add a lightweight endpoint for an instance running Amazon Linux 2023, install nginx and serve a path that returns 200:

sudo dnf install -y nginx sudo tee /etc/nginx/conf.d/health.conf >/dev/null <<'EOF' server { listen 8080; location = /health { access_log off; default_type text/plain; return 200 'ok'; } } EOF sudo nginx -t sudo systemctl enable --now nginx curl -I http://127.0.0.1:8080/health

The final curl command confirms that nginx is listening locally and returning a 200 response. Before you create the application status check, configure the instance security group to allow health check traffic on port 8080 from the same security group. For instructions, see Security group referencing.

Create an application status check

Create a check that requests /health on port 8080 over HTTP and treats 200 as healthy. Keep the default thresholds and set an initialization grace period so that newly launched instances have time to start.

aws ec2 create-application-status-check \ --protocol http \ --port 8080 \ --path /health \ --status-code-matcher "200" \ --initialization-grace-period-seconds 300 \ --tag-specifications 'ResourceType=application-status-check,Tags=[{Key=Name,Value=database-health}]'

The response returns an application status check ID, for example asc-0123456789abcdef0.

Name=database-health identifies the application status check. The app=database tag used in the next step selects the instances to monitor.

The status code matcher defaults to 200 and accepts a comma-separated list of individual codes or ranges, for example "200,204", up to 64 characters.

Associate the check with your instances

Use the application status check ID returned by the create step to associate the check with every instance that carries the app=database tag. Tag-based association covers instances that already carry the tag and instances that launch with it later, which suits an Auto Scaling group where replacement instances launch with the tag.

aws ec2 associate-application-status-check \ --application-status-check-id asc-0123456789abcdef0 \ --target-tag-associations Key=app,Value=database

You can also associate specific instances with --instance-ids instead of --target-tag-associations.

View the application status

The describe-instance-status call returns the application status alongside the instance and system status checks, so a query you already run surfaces it without a new API call.

aws ec2 describe-instance-status --instance-ids i-0abc123def4567890

The following example response shows a case where the system and instance status checks pass, while the application status reports impaired.

{ "InstanceStatuses": [ { "AvailabilityZone": "us-east-1d", "InstanceId": "i-0abc123def4567890", "InstanceState": { "Code": 16, "Name": "running" }, "SystemStatus": { "Status": "ok", "Details": [ { "Name": "reachability", "Status": "passed" } ] }, "InstanceStatus": { "Status": "ok", "Details": [ { "Name": "reachability", "Status": "passed" } ] }, "ApplicationStatus": { "Status": "impaired", "ImpairedSince": "2026-08-07T14:32:10.000Z" } } ] }

describe-instance-status returns the aggregation of the included application status checks associated with an instance. For details on every application status check associated with an instance, use describe-application-status, which returns each associated check’s individual result, the reason code, and the HTTP status code your application returned. Use describe-instance-status to see the aggregated application health next to other status checks, and describe-application-status for details on which check failed and why.

aws ec2 describe-application-status --instance-ids i-0abc123def4567890

A failed check includes a reason that explains the outcome. For example:

{ "ApplicationStatuses": [ { "InstanceId": "i-0abc123def4567890", "ApplicationStatus": { "Status": "impaired", "Details": [ { "ApplicationStatusCheckId": "asc-0123456789abcdef0", "Aggregation": "included", "Status": "failed", "Reason": { "Code": "ResponseCodeMismatch", "StatusCode": 503, "Protocol": "HTTP" } } ] } } ] }

For ResponseCodeMatched and ResponseCodeMismatch, the Reason includes the returned StatusCode and the Protocol, so you can distinguish a 500 from a 503. Connection reasons such as ConnectionTimeout, ConnectionRefused, and ConnectionReset indicate that the application did not complete a response at all, and do not include a StatusCode.

Replace instances with an impaired status check

When an application status check reports impaired, the right response depends on what failed, and not every impairment calls for terminating the instance. Common responses include rebooting the instance, rolling back a recent deployment, or terminating the instance and replacing it, and your workload may call for others. A transient fault may clear with a reboot, a bad deployment may call for a rollback, and a crashed or wedged instance usually calls for termination and replacement.

Amazon EC2 Auto Scaling evaluates the aggregated application status as part of its EC2 health checks. When the status is impaired, the group marks the instance unhealthy, terminates it, and attempts to launch a replacement from the group’s launch template. Auto Scaling does not copy the application from the terminated instance. Configure the AMI, user data, or deployment system for the group to install and start the application on each replacement. Because the group has fixed capacity in this example, it replaces the impaired instance rather than changing capacity. Auto Scaling includes application status checks in the group’s EC2 health checks by default, so no separate Auto Scaling health check configuration is required.

Terminate and replace is the default an Auto Scaling group gives you. If your remediation is a reboot or a rollback instead, keep the same impaired signal and act on it yourself, using the CloudWatch alarm in the next section to trigger your own automation.

Set the check’s InitializationGracePeriodSeconds to at least the time your application needs to start, and make sure the Auto Scaling group’s health check grace period is no shorter. Then neither the check nor the group acts on an instance that is still initializing. Detection and remediation then run without a separate monitoring system.

Alarm on the application status in Amazon CloudWatch

EC2 publishes the application status to CloudWatch, so you can alarm on it without a custom metric. This step is optional. Auto Scaling replaces an impaired instance whether or not you create an alarm. Add one when you want notification or a dashboard alongside the replacement. The following alarm notifies an operations topic when the application status check fails for an instance.

aws cloudwatch put-metric-alarm \ --alarm-name database-impaired \ --namespace AWS/EC2 \ --metric-name StatusCheckFailed_Application \ --dimensions Name=InstanceId,Value=i-0abc123def4567890 \ --statistic Maximum \ --period 60 \ --evaluation-periods 3 \ --threshold 1 \ --comparison-operator GreaterThanOrEqualToThreshold \ --alarm-actions arn:aws:sns:us-east-1:111122223333:ops-notifications

The alarm enters the ALARM state when the application status is impaired for three consecutive minutes. StatusCheckFailed_Application aggregates across every associated check whose aggregation is included. EC2 also publishes a per-check metric named StatusCheckFailed_Application_{application-status-check-id}, so you can alarm on an individual check when an instance has more than one associated.

To see the behavior end to end, stop the application process on one instance without stopping the instance. After the configured thresholds are met, the application status can turn impaired, the CloudWatch alarm can enter the ALARM state, and the Auto Scaling group can replace the instance while the remaining healthy instances can continue to serve traffic.

Rollout and maintenance strategies

Use the following strategies to stage deployment across your instances and suppress reporting during planned application maintenance.

Onboard checks across your instances

Roll application status checks out to a large number of instances in stages. An excluded check does not contribute to replacement decisions while you validate it.

Start in observe-only mode

Create the check with Aggregation set to excluded. An excluded check still runs and reports its result through describe-application-status and CloudWatch, but it does not contribute to the instance-level application status and does not cause Auto Scaling to replace an instance. Watch it for a representative period, confirm it returns the codes you expect, and tune the StatusCodeMatcher, FailureThreshold, SuccessThreshold, and initialization grace period. When you are confident, move the check to included with ModifyApplicationStatusCheck, and the result begins contributing to the instance-level status and to Auto Scaling replacement.

Associate by tag

Associate the check with a tag rather than a list of instance IDs. A tag-based association also covers a new instance when it launches with the tag, without another API call. This fits an Auto Scaling group, an instance refresh, or any workflow that replaces instances over time.

Amazon EKS and Karpenter

Application status checks can monitor an application endpoint on an EC2 worker node, including nodes launched for Amazon Elastic Kubernetes Service (Amazon EKS) managed node groups or by Karpenter. Each associated node must expose the HTTP or HTTPS health path on the configured port and carry the tag used by the check association. For an EKS managed node group, apply the tag to the EC2 instances through its custom launch template. For Karpenter, apply the tag through spec.tags in the EC2NodeClass. Application status checks monitor the endpoint on the EC2 instance, not a Kubernetes Service or an individual pod.

Manage checks as code

Define the check, its thresholds, and its tag association in the same infrastructure-as-code templates you use for your instances, so you can apply the same definition across environments and use your review process for changes. Roll the same definition out one Auto Scaling group or one Region at a time, and use a CloudWatch dashboard on the StatusCheckFailed_Application metric and the per-check StatusCheckFailed_Application_{application-status-check-id} metric to compare behavior before and after you switch a check to included.

The following template creates the check and its tag association. The template creates the check with Aggregation set to excluded so that it reports without contributing to the instance-level status, and you change it to included when you are ready.

Resources: DatabaseHealthCheck: Type: AWS::EC2::ApplicationStatusCheck Properties: Protocol: http Port: 8080 Path: /health StatusCodeMatcher: "200" FailureThreshold: 2 SuccessThreshold: 2 InitializationGracePeriodSeconds: 300 Aggregation: excluded Tags: - Key: Name Value: database-health DatabaseHealthCheckTagAssociation: Type: AWS::EC2::ApplicationStatusCheckTagAssociation Properties: ApplicationStatusCheckId: !GetAtt DatabaseHealthCheck.ApplicationStatusCheckId TagKey: app TagValue: database

The association takes the check ID, which the check exposes as an Fn::GetAtt attribute. To target named instances instead of a tag, use AWS::EC2::ApplicationStatusCheckInstanceAssociation with ApplicationStatusCheckId and InstanceId. Every ID property on both association resources is create-only, so changing the target replaces the association.

Run more than one check

You can associate more than one check with an instance, for example a liveness path and a readiness path, and include or exclude each from the aggregated instance-level status. Create a new check and exclude it from the aggregated count, confirm it behaves, then include it. The application status appears alongside the instance, system, and Amazon EBS status checks in describe-instance-status, so you can adopt it without changing the queries and alarms you already run.

Perform application maintenance

Planned maintenance, such as a rolling configuration change or a version upgrade, can make an application stop responding on its health path for a short time. Without a pause, the check reports the instance impaired and Auto Scaling can replace an instance that is healthy and only briefly offline. Pause reporting for the duration, then resume it.

The direct control is EnableApplicationStatusCheckSuppression. While suppression is in effect, the check does not mark instances impaired, so Auto Scaling does not act on it. Reporting resumes when you call DisableApplicationStatusCheckSuppression, or at the resume time set for the suppression. The following patterns wire that pause into common maintenance workflows.

EC2 Auto Scaling instance refresh and standby

An instance refresh rolls a new launch template through the group in batches and waits for each new instance to pass its health checks, including the application status check, before it continues. Set the check’s InitializationGracePeriodSeconds, and the group’s instance warmup, to at least the time your application needs to start, so the refresh does not act on an instance that is still initializing. For one-off manual work on a single instance, move it to standby with EnterStandby. The group stops health-checking and replacing it until you call ExitStandby.

AWS CodeDeploy

Suppression is not tied to any one deployment tool. If you deploy with AWS CodeDeploy, a deployment that restarts your application fails its health path until the new version is serving, so suppress the instance in a lifecycle hook before the deployment and resume it after. Suppress in a BeforeInstall hook and resume in an ApplicationStart hook in your appspec.yml:

version: 0.0 os: linux hooks: BeforeInstall: - location: scripts/suppress_status_check.sh timeout: 60 ApplicationStart: - location: scripts/resume_status_check.sh timeout: 60

scripts/suppress_status_check.sh suppresses the instance before the new version installs:

#!/bin/bash set -euo pipefail aws ec2 enable-application-status-check-suppression \ --instance-ids i-0abc123def4567890 \ --duration-seconds 600

scripts/resume_status_check.sh resumes reporting once the new version is up:

#!/bin/bash set -euo pipefail aws ec2 disable-application-status-check-suppression \ --instance-ids i-0abc123def4567890

The --duration-seconds value is a safety net: If the deployment fails before the resume hook runs, suppression lifts on its own rather than leaving the instance unmonitored. Omit it to suppress until you call disable. Grant the instance role ec2:EnableApplicationStatusCheckSuppression and ec2:DisableApplicationStatusCheckSuppression. After reporting resumes, the check evaluates the application again and returns the instance to healthy once it passes, so a routine deployment does not trigger a replacement.

AWS Systems Manager maintenance windows

For scheduled maintenance such as patching, run the work inside an AWS Systems Manager maintenance window and bracket it with the suppression calls: an automation step that enables suppression before the patch task and disables it after. Reporting stays paused for the window and resumes on its own at the suppression resume time if a step does not complete.

Clean up resources

Application status checks incur charges while they are associated with instances. AWS charges for each managed elastic network interface (ENI) AWS creates in your VPC, per Availability Zone, and standard Amazon CloudWatch rates apply to the metrics the checks publish. AWS creates one endpoint per combination of source subnet and security group, so the count does not scale per instance or per check. Delete the resources you created so that you do not incur further charges. Delete the application status check and the CloudWatch alarm, and delete the Auto Scaling group if you created it only for this walkthrough.

aws ec2 delete-application-status-check --application-status-check-id asc-0123456789abcdef0 aws cloudwatch delete-alarms --alarm-names database-impaired

Quotas

Application status checks are subject to service quotas that cap how many checks you create, how many associations you make, and how many instances you monitor. Review the current defaults before you roll out to a large number of instances, because a tag-based association covers instances that launch later. A growing number of instances can reach a quota without any change to your configuration. Once you pass a quota, the instances beyond it stop being checked and report no status. Use the Service Quotas console to view usage and request increases. For the current quotas and how each one is counted, see Application status checks in the Amazon EC2 User Guide.

Conclusion

In this post, we showed how to monitor application health on Amazon EC2 with application status checks. You created an HTTP check, associated it with your instances by tag, viewed the status alongside your existing status checks, alarmed on it in Amazon CloudWatch, and relied on Amazon EC2 Auto Scaling to replace an impaired instance. You can use EC2 status checks and Auto Scaling to detect and respond to application failures rather than operate a separate monitoring system.

If you use another deployment mechanism, apply the association tag to each EC2 instance and make sure the application exposes the configured health path and port. Contact your AWS account team if you need help adapting this pattern to your deployment process.

To learn more, see Application status checks in the Amazon EC2 User Guide and Health checks for instances in an Auto Scaling group in the Amazon EC2 Auto Scaling User Guide. As a next step, add a second check for a readiness path and exclude it from aggregation to see how per-check status contributes to the instance-level result.


About the author

Caroline Frost

Caroline Frost

Caroline is an Amazon EC2 Senior Product Manager – Technical, focusing on the EC2 instance lifecycle. She is passionate about building capabilities that improve the developer experience and create operational ease and simplicity.