← Back to DevBytes

Troubleshooting Elastic Beanstalk: Common Issues and Solutions

Introduction to Troubleshooting Elastic Beanstalk

AWS Elastic Beanstalk is a managed Platform-as-a-Service (PaaS) that simplifies deploying and scaling web applications. You upload your code, and Elastic Beanstalk automatically handles capacity provisioning, load balancing, auto-scaling, and application health monitoring. However, despite its abstraction, things can—and do—go wrong. Deployments fail, instances become degraded, environment variables go missing, and logs hide critical clues.

This tutorial walks you through the most common Elastic Beanstalk issues developers encounter and provides actionable solutions. Whether you are running a Node.js, Python, Java, or Docker environment, the troubleshooting principles here apply broadly.

Why Troubleshooting Skills Matter

Elastic Beanstalk hides much of the underlying infrastructure complexity, but that abstraction can become a liability when something breaks. Without a solid understanding of how Beanstalk orchestrates EC2 instances, Auto Scaling groups, Elastic Load Balancers, and CloudWatch, you may find yourself stuck staring at a red "Degraded" status with no clear path forward. Mastering troubleshooting techniques reduces downtime, accelerates incident response, and helps you design more resilient deployments.

Understanding the Elastic Beanstalk Architecture

Before diving into specific issues, it helps to understand the components involved in a typical Elastic Beanstalk environment:

Most issues fall into one of these categories: deployment failures, instance health problems, configuration errors, networking/permissions issues, or application-level bugs exposed only in production.

Issue 1: Deployment Failures

Deployment failures are the most frequent issue. The environment status flips to "Degraded" or "Info" with a rollback, and the event log shows messages like "Instance deployment failed" or "Command failed on instance."

Diagnosing Deployment Failures

Start by reviewing the environment events in the AWS Console or via the EB CLI:

eb events --environment my-app-env

For deeper detail, fetch the deployment logs. The most useful file is /var/log/eb-engine.log, which records every deployment step:

eb ssh --environment my-app-env
sudo tail -n 200 /var/log/eb-engine.log

Common causes include missing dependencies, syntax errors in .ebextensions, or a failing container command.

Fixing a Failing .ebextensions Command

Suppose your .ebextensions/01_packages.config contains a command that exits with a non-zero status. Elastic Beanstalk treats any non-zero exit code as a deployment failure. Here is a problematic example:

commands:
  01_install_redis:
    command: "yum install -y redis"
    cwd: /tmp

If the package is unavailable or the command fails, the deployment halts. Add error handling and logging:

commands:
  01_install_redis:
    command: "yum install -y redis && echo 'redis installed' >> /var/log/custom-deploy.log || (echo 'redis install failed' >> /var/log/custom-deploy.log; exit 1)"
    cwd: /tmp

This ensures you capture diagnostic output even when the command fails, and you can inspect /var/log/custom-deploy.log after SSH-ing into the instance.

Handling Rollbacks

If your environment is configured to roll back on deployment failure, Beanstalk reverts to the last known good version. To disable this during debugging, update the environment:

eb setenv --environment my-app-env
aws elasticbeanstalk update-environment \
  --environment-name my-app-env \
  --option-settings Namespace=aws:elasticbeanstalk:command,OptionName=DeploymentPolicy,Value=Rolling

Switching to a Rolling deployment policy (instead of Immutable) lets you inspect the failed instance directly before it is terminated.

Issue 2: Instances Stuck in "Degraded" or "Severe" Health

When Beanstalk reports degraded health, it means one or more instances are failing health checks. The load balancer periodically pings a health check URL (default /); if it does not return a 200 OK within the timeout, the instance is marked unhealthy.

Investigating Health Check Failures

First, verify the health check path matches a route your application actually serves. For a Node.js Express app, ensure there is a handler at the configured path:

app.get('/health', (req, res) => {
  res.status(200).json({ status: 'ok' });
});

Then configure Beanstalk to use /health as the health check URL:

aws elasticbeanstalk update-environment \
  --environment-name my-app-env \
  --option-settings Namespace=aws:elasticbeanstalk:application,OptionName=Application Healthcheck URL,Value=/health

Next, check Nginx access and error logs on the instance:

eb ssh --environment my-app-env
sudo tail -n 100 /var/log/nginx/access.log
sudo tail -n 100 /var/log/nginx/error.log

Look for 502 Bad Gateway errors, which typically indicate the application process crashed or is not listening on the expected port.

Verifying the Application Port

Elastic Beanstalk expects your application to listen on the port specified by the PORT environment variable. A common mistake is hardcoding the port:

// Wrong - hardcoded port
app.listen(3000);

Use the environment variable instead:

// Correct - respects Beanstalk's PORT
const port = process.env.PORT || 3000;
app.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

If the app listens on 3000 but Nginx proxies to 8081 (the default for Node.js platforms), every request returns a 502.

Issue 3: Environment Variables Not Applied

Developers frequently report that environment properties set in the Beanstalk console are not visible to their application. This usually stems from a mismatch between where the variables are stored and where the application reads them.

How Beanstalk Injects Environment Variables

Beanstalk writes environment properties to /opt/elasticbeanstalk/deployment/env and exports them to the application process. For Docker-based environments, the variables are passed to the container differently. Verify what is actually set on a running instance:

eb ssh --environment my-app-env
sudo cat /opt/elasticbeanstalk/deployment/env | grep DATABASE_URL

If the variable is missing, it may not have been saved or the deployment did not pick it up. Re-apply environment properties:

eb setenv DATABASE_URL=postgres://user:pass@host:5432/db SECRET_KEY=mysecret

This triggers a lightweight environment update that propagates the variables without redeploying code.

Docker-Specific Variable Handling

For Docker platforms, pass environment variables through a docker-compose.yml or a Dockerrun.aws.json file. Here is an example docker-compose.yml that forwards Beanstalk environment variables into the container:

version: '3.8'
services:
  web:
    image: my-app:latest
    ports:
      - "8080:8080"
    environment:
      - DATABASE_URL
      - SECRET_KEY
      - PORT=8080

Variables listed without a value are inherited from the host environment, which is exactly how Beanstalk injects them.

Issue 4: Permission and IAM Errors

Elastic Beanstalk relies on several IAM roles: the service role, the EC2 instance profile, and any custom roles your application assumes. Misconfigured permissions cause silent failures, such as instances unable to write logs to S3 or pull images from ECR.

Common Permission Symptoms

Fixing the EC2 Instance Profile

Attach a policy that grants the necessary permissions. At minimum, the instance profile needs aws-elasticbeanstalk-ec2-role managed policies. For pulling from ECR, add an inline policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:GetAuthorizationToken"
      ],
      "Resource": "*"
    }
  ]
}

Attach it to the instance profile used by your environment:

aws iam put-role-policy \
  --role-name aws-elasticbeanstalk-ec2-role \
  --policy-name EcrPullAccess \
  --policy-document file://ecr-policy.json

After updating the policy, restart instances or trigger a deployment so the new permissions take effect:

eb restart --environment my-app-env

Issue 5: Custom Platform Hooks and .ebextensions Not Running

On Amazon Linux 2 and AL2023 platforms, Beanstalk introduced .platform/hooks as the preferred mechanism for customization, replacing many .ebextensions use cases. A frequent issue is hooks silently not executing.

Common Hook Problems

Correct Hook Structure

Place pre-deployment hooks in .platform/hooks/prebuild/, post-deployment hooks in .platform/hooks/postdeploy/. Here is a valid postdeploy hook that warms the application cache:

#!/bin/bash
# .platform/hooks/postdeploy/01_warm_cache.sh

curl -s http://localhost:8080/warm-cache > /dev/null
if [ $? -ne 0 ]; then
  echo "Cache warm-up failed" >> /var/log/custom-hooks.log
  exit 1
fi
echo "Cache warmed successfully" >> /var/log/custom-hooks.log

Ensure the file is executable and uses Unix line endings. Add this to your build pipeline or commit the file with the correct permissions:

chmod +x .platform/hooks/postdeploy/01_warm_cache.sh
git update-index --chmod=+x .platform/hooks/postdeploy/01_warm_cache.sh

Verify hook execution by inspecting /var/log/eb-engine.log after deployment:

eb ssh --environment my-app-env
sudo grep -i "postdeploy" /var/log/eb-engine.log

Issue 6: Log Rotation and Missing Logs

Beanstalk rotates logs and can upload them to S3 on request, but sometimes logs disappear or are incomplete. This happens when the application writes to non-standard locations that logrotate does not know about.

Adding Custom Log Rotation

Create a logrotate configuration via .ebextensions to handle custom log files:

files:
  "/etc/logrotate.d/custom-app":
    content: |
      /var/app/current/logs/*.log {
        daily
        rotate 7
        compress
        missingok
        notifempty
        copytruncate
      }
    mode: "000644"
    owner: root
    group: root

To enable log streaming to CloudWatch, configure it in the environment settings:

aws elasticbeanstalk update-environment \
  --environment-name my-app-env \
  --option-settings \
    Namespace=aws:elasticbeanstalk:cloudwatch:logs,OptionName=StreamLogs,Value=true \
    Namespace=aws:elasticbeanstalk:cloudwatch:logs,OptionName=DeleteOnTerminate,Value=false \
    Namespace=aws:elasticbeanstalk:cloudwatch:logs,OptionName=RetentionInDays,Value=14

With log streaming enabled, you can query logs in CloudWatch Logs Insights without SSH-ing into instances:

aws logs start-query \
  --log-group-name /aws/elasticbeanstalk/my-app-env/var/log/eb-engine.log \
  --start-time $(date -d '1 hour ago' +%s) \
  --end-time $(date +%s) \
  --query-string 'fields @timestamp, @message | filter @message like /ERROR/ | sort @timestamp desc | limit 50'

Issue 7: Auto Scaling and Capacity Problems

Applications sometimes fail to scale or scale too aggressively, leading to either overloaded instances or unnecessary cost. Understanding the default scaling triggers helps diagnose these issues.

Reviewing Scaling Policies

Check the current Auto Scaling group configuration:

aws autoscaling describe-auto-scaling-groups \
  --auto-scaling-group-names awseb-my-app-env-stack-AutoScalingGroup-ABC123

Inspect the scaling policies attached to the group:

aws autoscaling describe-policies \
  --auto-scaling-group-name awseb-my-app-env-stack-AutoScalingGroup-ABC123

If CPU-based scaling is too aggressive for your workload, switch to request-count-based scaling by updating the environment:

aws elasticbeanstalk update-environment \
  --environment-name my-app-env \
  --option-settings \
    Namespace=aws:autoscaling:trigger,OptionName=MeasureName,Value=RequestCount \
    Namespace=aws:autoscaling:trigger,OptionName=Statistic,OptionValue=Sum \
    Namespace=aws:autoscaling:trigger,OptionName=Unit,Value=Count \
    Namespace=aws:autoscaling:trigger,OptionName=Period,Value=60 \
    Namespace=aws:autoscaling:trigger,OptionName=LowerThreshold,Value=100 \
    Namespace=aws:autoscaling:trigger,OptionName=UpperThreshold,Value=500

This scales out when requests exceed 500 per minute and scales in when they drop below 100, which is often more predictable than CPU utilization for web workloads.

Best Practices for Elastic Beanstalk Reliability

1. Always Use Versioned Configuration

Store environment configurations as saved templates in source control. Export and commit them:

eb config save --environment my-app-env --cfg my-app-prod

This produces a YAML file in .elasticbeanstalk/saved_configs/ that you can version, review, and reuse.

2. Implement a Dedicated Health Endpoint

Do not use your root path for health checks. A dedicated endpoint that verifies critical dependencies (database, cache) provides more accurate health signals:

app.get('/health', async (req, res) => {
  try {
    await db.raw('SELECT 1');
    await redis.ping();
    res.status(200).json({ status: 'healthy' });
  } catch (err) {
    res.status(503).json({ status: 'unhealthy', error: err.message });
  }
});

3. Enable Enhanced Health Reporting

Enhanced health reporting gives granular metrics and faster detection of issues. Enable it via service role assignment:

aws elasticbeanstalk update-environment \
  --environment-name my-app-env \
  --option-settings Namespace=aws:elasticbeanstalk:healthreporting:system,OptionName=SystemType,Value=enhanced

4. Use Immutable Deployments for Production

Immutable deployments spin up a fresh Auto Scaling group, deploy the new version, and only swap traffic if all instances pass health checks. This prevents bad deployments from impacting live traffic:

aws elasticbeanstalk update-environment \
  --environment-name my-app-env \
  --option-settings Namespace=aws:elasticbeanstalk:command,OptionName=DeploymentPolicy,Value=Immutable

5. Set Up CloudWatch Alarms

Create alarms for key metrics so you are alerted before users notice problems:

aws cloudwatch put-metric-alarm \
  --alarm-name "Beanstalk-High-5xx-Errors" \
  --alarm-description "Alert when 5xx errors exceed threshold" \
  --metric-name HTTPCode_Target_5XX_Count \
  --namespace AWS/ApplicationELB \
  --statistic Sum \
  --period 60 \
  --threshold 10 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 2 \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:alerts

6. Test Deployments in a Staging Environment

Maintain a staging environment that mirrors production. Promote the same application version from staging to production only after validation:

# Deploy to staging
eb deploy my-app-staging

# After validation, swap to production
eb appversion --environment my-app-prod --label v1.2.3

Conclusion

Troubleshooting Elastic Beanstalk effectively requires understanding the layers beneath the abstraction: EC2 instances, load balancers, Auto Scaling groups, IAM roles, and the deployment lifecycle. By systematically examining event logs, engine logs, Nginx logs, and CloudWatch metrics, you can pinpoint the root cause of most issues quickly. The key habits are maintaining versioned configurations, implementing meaningful health checks, enabling enhanced health reporting and log streaming, and testing deployments in staging before promoting to production. With these practices and the specific solutions outlined in this tutorial, you will be equipped to resolve the most common Elastic Beanstalk problems and keep your applications running reliably at scale.

— Ad —

Google AdSense will appear here after approval

← Back to all articles