Amazon EC2 Application Status Checks: Setup Guide and Auto Scaling Integration
Amazon EC2 Application Status Checks: Setup Guide and Auto Scaling Integration
On August 12, 2026, AWS shipped a status check type EC2 has never had: one that actually asks your application whether it's healthy, instead of asking the VM. The existing system and instance status checks only tell you the hypervisor is fine and the instance is booted โ neither one notices a hung web server, a dead Docker daemon, or an app stuck returning 500s while the OS underneath it looks perfectly healthy. Teams have worked around this for years with a Lambda cron hitting a /health endpoint, or by only getting this behavior for free inside an ALB target group. Application status checks bring that capability directly to EC2 instances and wire it straight into Auto Scaling. Here's how it actually works, how to set it up, and the deployment gotcha that will bite you if you skip it.
Why this is a different check than what you already have
EC2 has always run two status checks automatically: a system status check (is the underlying hardware/hypervisor healthy) and an instance status check (is your instance's software/network configuration responding). Both pass as long as the VM itself is fine โ they have no idea whether the process you actually care about is serving traffic.
Application status checks close that gap. AWS sends an HTTP or HTTPS request to a port and path you configure, every 60 seconds, and compares the response code against a status code matcher you define. Fail enough consecutive checks and the instance's application status flips to impaired โ and if the check is associated with an Auto Scaling group, that impaired instance gets replaced automatically, the same way ASG already replaces instances that fail the built-in checks.
The traffic doesn't come from the public internet. AWS creates a managed elastic network interface (ENI) inside your VPC โ one per distinct subnet-and-security-group combination among your monitored instances โ and the check runs over the private network path from that ENI. You don't manage this ENI directly, but its existence does count against your account's Network interfaces per Region quota, which matters once you're monitoring hundreds of instances.
Step 1 โ Prepare your application and security group
Before creating a check, make sure:
- Your application actually serves an HTTP/HTTPS endpoint on a known port and path that returns a success code when healthy (e.g.,
GET /healthโ200). - The destination instance's security group allows inbound traffic on that port from the check's source security group. With AWS managed network paths (the default), AWS provides this source security group automatically when you create the check.
Step 2 โ Create the check definition
Application status checks are created and managed primarily through the AWS CLI (the console has an equivalent flow under EC2 โ Instances โ Application status checks). The simplest form lets AWS manage the network path for you:
1aws ec2 create-application-status-check \
2 --protocol https \
3 --port 443 \
4 --path "/health" \
5 --status-code-matcher "200"
If your VPC has strict network segmentation and you need to control exactly which subnet and security group the health-check traffic originates from, specify it explicitly instead:
1aws ec2 create-application-status-check \
2 --protocol https \
3 --port 443 \
4 --path "/health" \
5 --status-code-matcher "200" \
6 --health-check-paths '[{"Source":{"SubnetId":"subnet-111","SecurityGroupId":"sg-aaa"},"Destinations":[{"SubnetId":"subnet-222","SecurityGroupId":"sg-bbb"}]}]'
The check interval is fixed at 60 seconds and isn't configurable. What you can tune: FailureThreshold and SuccessThreshold (both default to 2 consecutive results), Timeout (default 6 seconds, 1โ30 range), and InitializationGracePeriodSeconds โ how long AWS waits after instance launch before it starts evaluating the check (default 300 seconds, 1โ600 range). Set that grace period to actually cover your app's real startup time, not a guess โ too short, and Auto Scaling can terminate a perfectly good instance before its application has finished starting.
Step 3 โ Associate the check with instances
A check definition alone does nothing until you associate it with instances, either by instance ID or by tag:
1# By instance ID
2aws ec2 associate-application-status-check \
3 --application-status-check-id asc-1234567890abcdef0 \
4 --instance-ids i-0123456789abcdef0
5
6# By tag โ associates with every current and future instance carrying the tag
7aws ec2 associate-application-status-check \
8 --application-status-check-id asc-1234567890abcdef0 \
9 --target-tag-associations Key=Environment,Value=production
To cover an entire Auto Scaling group, associate by the ASG's own system tag instead of hunting down individual instance IDs:
1aws ec2 associate-application-status-check \
2 --application-status-check-id asc-1234567890abcdef0 \
3 --target-tag-associations Key=aws:autoscaling:groupName,Value=my-asg
Step 4 โ Verify results before trusting them
Check the per-instance overall status and each individual check's result:
1aws ec2 describe-application-status --instance-ids i-0123456789abcdef0
A healthy instance returns "Status": "ok" with a ResponseCodeMatched reason on each associated check. describe-instance-status also now surfaces the aggregated application status alongside your existing system/instance checks, if you already poll that command as part of a monitoring script.
Auto Scaling integration โ and the grace period trap
Once a check is associated with instances in an Auto Scaling group, no extra ASG configuration is required โ Auto Scaling automatically terminates and replaces any instance whose overall application status reports impaired. But there are two separate grace periods here, and conflating them is the single most common misconfiguration:
- The check's own
InitializationGracePeriodSecondscontrols when the check itself starts evaluating the application after launch. - The Auto Scaling group's health check grace period controls how long ASG waits after an instance enters service before it acts on a failing health check.
Set both to actually cover your application's real startup time. If either is too short, you'll see brand-new instances get terminated and replaced in a loop before the app ever finishes booting โ which looks like a deployment failure but is really just a grace period that's shorter than your actual startup time.
Also set an instance maintenance policy on the Auto Scaling group if you haven't already. A health check that depends on a shared resource (a database connection, a downstream service) can fail across your entire fleet simultaneously, and without a maintenance policy limiting concurrent replacements, that's a self-inflicted mass termination event, not a gentle rolling fix.
Handling deployments without triggering false replacements
Application status checks report failed any time your app can't respond โ including during a normal, intentional deployment or in-place patch. If that check is included in aggregation on an ASG instance, Auto Scaling can terminate the instance mid-deploy, which is exactly the wrong reaction to a planned restart.
For bounded maintenance windows, suppress the check instead of disassociating it:
1aws ec2 enable-application-status-check-suppression \
2 --instance-ids i-0123456789abcdef0 \
3 --duration-seconds 3600
4
5# resume checking before the window expires, if needed
6aws ec2 disable-application-status-check-suppression \
7 --instance-ids i-0123456789abcdef0
While suppressed, the instance reports suppressed and Auto Scaling won't act on it. Wire this into your deployment tooling: call enable-application-status-check-suppression in your pre-deploy hook and disable-application-status-check-suppression in your post-deploy hook, so the suppression window always matches the actual deployment window instead of a hardcoded guess.
For longer-lived validation โ testing a brand-new check against production traffic without risking a replacement โ set the check's aggregation to excluded instead. It keeps reporting its individual status for you to inspect, but doesn't count toward the overall status or drive Auto Scaling until you flip it to included.
Best practices
- Point the health endpoint at the instance's own health, not a shared dependency. If
/healthalso checks a shared database, one database blip fails the check on every instance simultaneously and can trigger a fleet-wide replacement wave instead of fixing the one instance that's actually broken. - Set an instance maintenance policy on the ASG to cap how many instances get replaced at once, so a correlated failure doesn't turn into a stampede.
- Alarm on
StatusCheckFailed_Application, not just individual failures. CloudWatch publishes this metric per instance, plus a per-check metric namedStatusCheckFailed_Application_{check-id}. A sudden spike across many instances at once is a shared-dependency problem, not five unrelated instance failures โ and it gives you a window to react before Auto Scaling starts replacing things. - Treat the IAM actions that manage these checks as change-controlled, not bundled into general EC2 access โ
CreateApplicationStatusCheck,AssociateApplicationStatusCheck,ModifyApplicationStatusCheck, andEnableApplicationStatusCheckSuppressioncan all directly cause instance terminations if misused. - Consolidate monitored instances into fewer subnet/security-group combinations where practical โ the managed ENI count scales with the number of distinct combinations, and each one eats into your per-AZ network interface quota.
Common mistakes to avoid
- Setting
InitializationGracePeriodSecondsshorter than your actual app startup time. This causes a replace-loop that looks like a deploy failure. - Health endpoint returns a redirect (301/302). Health check calls don't follow redirects โ either point the check at the final destination or add the redirect code to your status code matcher.
- Protocol mismatch โ configuring the check as HTTPS against an app that only serves plain HTTP (or vice versa) fails every single request.
- Forgetting the security group rule. The destination instance's security group has to explicitly allow inbound traffic from the check's source security group on the check port โ this is the most common "why is everything impaired" cause.
- Deploying without suppressing the check first. A normal restart during deployment reads as an application failure to Auto Scaling unless you suppress or exclude the check around the maintenance window.
Troubleshooting
If a check reports impaired but you believe the application is fine, work through this in order:
- Confirm the instance's existing system and instance status checks are
okfirst โ if the VM itself is unhealthy, the application check failing is a symptom, not the root cause. - Confirm the security group allows inbound traffic on the check port from the check's source security group.
- Confirm there's no host-level firewall (iptables, Windows Firewall) blocking the port.
- SSH/RDP in and curl the endpoint locally:
curl http://localhost:PORT/PATHโ confirm it actually responds the way you expect. - Double-check the protocol (HTTP vs HTTPS) matches what your app actually serves.
- Confirm your status code matcher actually includes the code your app returns for a healthy response.
The describe-application-status response includes a reason code for every failure, which shortcuts most of this diagnosis:
| Reason code | Meaning |
|---|---|
ResponseCodeMismatch | App responded, but not with a code in your status code matcher |
ConnectionTimeout | Couldn't establish a connection to the target at all |
ResponseTimeout | Connected, but no response within the Timeout window |
ConnectionRefused | Target actively refused the connection (nothing listening on that port) |
ConnectionReset | Connection was reset before a response came back |
FAQ
Does this replace ALB target group health checks? No โ it's a separate mechanism for instances that aren't behind an ALB, or where you want application-level health visibility independent of load balancer routing. If your instances are already behind an ALB with target group health checks configured, you likely don't need to duplicate that logic here, but you can still use application status checks for CloudWatch alarming and Auto Scaling replacement decisions outside the load balancer's own health-based routing.
What does it cost? $0.01 per hour for each managed ENI, per Availability Zone, plus standard CloudWatch pricing for the metrics it publishes. The ENI count depends on how many distinct subnet/security-group combinations your monitored instances span, not the number of instances directly.
Does it work during a reboot? It reports a failure during a reboot, because the application genuinely can't respond while the OS is restarting โ this is expected, not a bug. Suppress the check if the reboot is planned and the instance is in an ASG.
Is this available everywhere? All commercial AWS Regions and AWS GovCloud (US) Regions, as of the August 12, 2026 launch.
What's the default quota if I want to roll this out broadly? 50 health checks per account, 50 associations per check, 200 associations per account, and 5,000 monitored targets per account by default โ most of these auto-scale on request except the targets quota, which needs a manual increase request.
Key takeaways
| Question | Answer |
|---|---|
| What it checks | Your application's actual HTTP/HTTPS response, not just the VM |
| Check interval | Fixed at 60 seconds |
| Default failure/success threshold | 2 consecutive results each way |
| Create via | aws ec2 create-application-status-check |
| Associate via | Instance ID, arbitrary tag, or aws:autoscaling:groupName |
| Auto Scaling behavior | Replaces instances whose overall status is impaired, once associated |
| Deployment handling | Suppress with enable-application-status-check-suppression before planned restarts |
| CloudWatch metric | StatusCheckFailed_Application (fleet-wide) and per-check variants |
| Cost | $0.01/hour per managed ENI per AZ, plus standard CloudWatch pricing |
Further Reading
- CloudWatch Managed Prometheus Collectors: Setup Guide for EC2 and ECS โ pairs well with this if you're building out EC2 observability beyond basic health checks.
- Create AWS IAM Role for EC2 โ background if you're setting up the IAM permissions that gate who can create or modify these checks.
- Monitor APIs via AWS Lambda and Cloudwatch โ the manual, Lambda-based approach teams used before this feature existed, useful context for what native application status checks now replace.
- Official announcement: Amazon EC2 introduces application status checks
- Official docs: Application status checks โ Amazon EC2 User Guide