AWS Elastic Beanstalk: Zero-Config PaaS for Web Applications (2026)
AWS Elastic Beanstalk is the forgotten gem of AWS's compute portfolio. While everyone debates ECS vs EKS, Beanstalk quietly deploys production Spring Boot APIs, Python Flask apps, and Node.js services for thousands of teams — with zero infrastructure code required. You upload a JAR, Beanstalk provisions the load balancer, Auto Scaling group, EC2 instances, and CloudWatch alarms. You get a fully managed PaaS on top of familiar AWS infrastructure, which means you can always reach through Beanstalk to the underlying resources when you need to. This guide covers everything: EB CLI workflows, the powerful .ebextensions configuration system, every deployment policy explained with real trade-offs, RDS integration patterns, Secrets Manager, and a complete CI/CD pipeline with CodePipeline.
Table of Contents
- Beanstalk vs ECS vs EC2 vs App Runner — Decision Guide
- Supported Platforms and Runtimes
- EB CLI: Init, Create, Deploy
- Customizing Environments with .ebextensions
- Deployment Policies: All at Once to Blue/Green
- Environment Variables and Secrets Manager Integration
- RDS Integration: Coupled vs Decoupled Database
- Custom Platform Hooks: Procfile and Buildfile
- CI/CD with CodePipeline and Terraform
- Monitoring, Enhanced Health, and Managed Updates
- FAQ
Beanstalk vs ECS vs EC2 vs App Runner — Decision Guide
AWS offers four primary ways to run web applications, and choosing the wrong abstraction level costs you weeks of rework. The decision comes down to how much infrastructure control you need versus how much operational overhead you can accept.
| Factor | Elastic Beanstalk | ECS Fargate | EC2 Direct | App Runner |
|---|---|---|---|---|
| Infrastructure management | Automatic (but inspectable) | Control plane managed, you define tasks | Full manual control | Fully managed, zero config |
| Deployment artifact | ZIP/JAR/WAR or Docker | Docker image only | AMI / user-data scripts | Docker image or source repo |
| Custom OS-level config | Yes, via .ebextensions | Via custom Docker image | Full access | No |
| Built-in load balancer | Yes (ALB/NLB/Classic) | Yes (ALB/NLB) | Manual setup | Yes (built-in) |
| Auto Scaling | Yes, ASG-based | Yes, ECS auto scaling | Manual or ASG | Automatic, request-based |
| Worker tier support | Yes (SQS-driven worker tier) | Via ECS tasks | Manual | No |
| Cost model | Pay for EC2/ALB only | Pay per vCPU/memory second | Pay for EC2/ALB | Higher per-request, simpler billing |
| CI/CD integration | Excellent (CodePipeline native) | Good | Manual | GitHub/ECR auto-deploy |
| Best for | Existing JAR/WAR apps, .NET, teams new to AWS | Microservices, mixed workloads, containers | Legacy lift-and-shift, max control | Simple APIs, startups, no DevOps team |
eb ssh when things go wrong — unlike App Runner's black box.
Beanstalk is not the right choice when you have dozens of containerized microservices (use ECS/EKS), when you need fine-grained Kubernetes features like custom schedulers or service meshes (use EKS), or when you need a truly serverless auto-scaling-to-zero model (use Lambda or App Runner).
Supported Platforms and Runtimes
Elastic Beanstalk supports a wide range of managed platform branches. Each platform is versioned independently and receives AWS-managed security patches. As of 2026, the supported platform branches include:
| Platform | Solution Stack Example | Notes |
|---|---|---|
| Java (Corretto 21) | 64bit Amazon Linux 2023/... running Corretto 21 | Runs JAR directly; Tomcat variant for WAR files |
| Java (Tomcat 10) | 64bit Amazon Linux 2023/... running Tomcat 10 Corretto 21 | Legacy WAR deployments |
| Python 3.11 | 64bit Amazon Linux 2023/... running Python 3.11 | WSGI via Gunicorn (default) or uWSGI |
| Node.js 20 | 64bit Amazon Linux 2023/... running Node.js 20 | npm start or Procfile |
| Docker | 64bit Amazon Linux 2023/... running Docker | Single container; use ECS for multi-container |
| .NET Core on Linux | 64bit Amazon Linux 2023/... running .NET 8 | Deploy .zip of published .NET app |
| Go 1.21 | 64bit Amazon Linux 2023/... running Go 1.21 | Procfile-driven |
| Ruby 3.2 | 64bit Amazon Linux 2023/... running Ruby 3.2 | Puma or Passenger |
| PHP 8.2 | 64bit Amazon Linux 2023/... running PHP 8.2 | Apache httpd |
dnf instead of yum — update your .ebextensions package manager references accordingly.
You can list current solution stacks with the AWS CLI:
aws elasticbeanstalk list-available-solution-stacks \
--query "SolutionStacks[?contains(@,'Corretto 21')]" \
--output text
EB CLI: Init, Create, Deploy
The EB CLI is the primary tool for Elastic Beanstalk workflows. Install it with pip and use it from your project root. It creates a .elasticbeanstalk/config.yml file that tracks your application and environment settings.
# Install EB CLI
pip install awsebcli --upgrade --user
# Verify
eb --version
# EB CLI 3.21.x (Python 3.x)
# Initialise in your project root
cd my-spring-boot-app
eb init
# The CLI prompts:
# Select a default region: us-east-1
# Application name: my-spring-boot-app
# Select a platform: Java
# Select a platform branch: Corretto 21 running on 64bit Amazon Linux 2023
# Do you want to set up SSH? Yes
# Select a keypair or create new
After eb init, your .elasticbeanstalk/config.yml looks like this:
branch-defaults:
main:
environment: my-app-prod
group_suffix: null
global:
application_name: my-spring-boot-app
branch: null
default_ec2_keyname: my-keypair
default_platform: Corretto 21 running on 64bit Amazon Linux 2023
default_region: us-east-1
include_git_submodules: true
instance_profile: null
platform_name: null
platform_version: null
profile: null
repository: null
sc: git
workspace_type: Application
Now create your first environment. A Beanstalk environment is the combination of EC2 instances, a load balancer, Auto Scaling group, and all related resources.
# Create a Web Server environment (load balanced)
eb create my-app-prod \
--tier webserver \
--elb-type application \
--instance-type t3.small \
--min-instances 2 \
--max-instances 6 \
--envvars SPRING_PROFILES_ACTIVE=prod,DB_HOST=prod-db.cluster.us-east-1.rds.amazonaws.com
# This takes ~5 minutes. Beanstalk creates:
# - An ALB with target group
# - An Auto Scaling group (min 2, max 6)
# - EC2 instances running Corretto 21
# - Security groups for ALB and instances
# - CloudWatch alarms for CPU/network
# Create a Worker tier environment (SQS-driven background processing)
eb create my-app-worker \
--tier worker \
--instance-type t3.small
Deploying your Spring Boot application is a single command. Beanstalk uploads your artifact to S3, distributes it to instances, and restarts the application server.
# Build the Spring Boot JAR
./mvnw clean package -DskipTests
# Deploy
eb deploy my-app-prod
# Watch the event stream
eb events -f my-app-prod
# Check environment status
eb status my-app-prod
# Open in browser
eb open my-app-prod
# SSH into a running instance
eb ssh my-app-prod
# View live logs
eb logs my-app-prod
eb deploy packages your git working tree. To deploy a specific JAR, use eb deploy --label v1.2.3 --message "Release 1.2.3" combined with a .ebignore file that excludes source files and only packages target/myapp.jar.
Customizing Environments with .ebextensions
The .ebextensions directory is Beanstalk's secret superpower. Place YAML configuration files inside .ebextensions/ in your deployment ZIP, and Beanstalk's cfn-init processes them in alphabetical order on every EC2 instance during launch and deployment. You can install OS packages, write files, run shell commands, and set environment variables — without touching the underlying CloudFormation templates.
The five main keys in an .ebextensions config file are packages, files, commands, container_commands, and option_settings. The critical difference between commands and container_commands: commands run before the application is deployed; container_commands run after the new application version is staged but before it goes live — perfect for database migrations.
# .ebextensions/01-packages.config
packages:
dnf: # Amazon Linux 2023 uses dnf
git: []
jq: []
htop: []
rpm:
newrelic-infra: https://download.newrelic.com/infrastructure_agent/linux/rpm/x86_64/newrelic-infra.x86_64.rpm
# .ebextensions/02-nginx.config
# Override the default Nginx proxy config for Spring Boot
files:
"/etc/nginx/conf.d/proxy.conf":
mode: "000644"
owner: root
group: root
content: |
upstream springboot {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 80;
gzip on;
gzip_types text/plain application/json application/javascript text/css;
gzip_min_length 1024;
location / {
proxy_pass http://springboot;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_connect_timeout 30s;
client_max_body_size 100m;
}
location /health {
proxy_pass http://springboot/actuator/health;
}
}
commands:
01-reload-nginx:
command: "nginx -s reload || true"
ignoreErrors: true
# .ebextensions/03-env.config
# Set JVM options via the environment
option_settings:
aws:elasticbeanstalk:application:environment:
SERVER_PORT: "8080"
JAVA_TOOL_OPTIONS: "-Xms512m -Xmx1024m -XX:+UseG1GC -Djava.net.preferIPv4Stack=true"
aws:elasticbeanstalk:environment:proxy:
ProxyServer: nginx
aws:autoscaling:asg:
MinSize: "2"
MaxSize: "6"
aws:autoscaling:trigger:
MeasureName: CPUUtilization
Threshold: "70"
LowerThreshold: "30"
Period: "5"
EvaluationPeriods: "2"
Unit: Percent
# .ebextensions/04-migrations.config
# Run Flyway migrations before the new version goes live
container_commands:
01-run-migrations:
command: |
java -jar /var/app/staging/target/myapp.jar \
--spring.profiles.active=migrate \
--spring.main.web-application-type=none
leader_only: true # Only run on one instance in the ASG
# .ebextensions/05-cron.config
# Add a cron job to the ec2-user crontab
files:
"/etc/cron.d/cleanup":
mode: "000644"
owner: root
group: root
content: |
# Purge temp files every hour
0 * * * * ec2-user find /tmp -name "upload_*" -mmin +60 -delete
commands:
01-restart-crond:
command: "systemctl restart crond"
yum: under packages:, change it to dnf: for Amazon Linux 2023 platform branches. The syntax is otherwise identical.
Deployment Policies: All at Once to Blue/Green
Beanstalk's deployment policies control how a new application version is distributed across the running instances. Choosing the right policy balances deployment speed against availability risk — a critical decision for production environments.
| Policy | Downtime? | Extra capacity? | Rollback speed | Best for |
|---|---|---|---|---|
| All at once | Yes (brief) | No | Another full deployment | Dev/test, non-critical |
| Rolling | No (reduced capacity) | No | Another rolling deployment | Non-peak production |
| Rolling with additional batch | No (full capacity) | Yes (1 batch) | Another rolling deployment | Production, cost-sensitive |
| Immutable | No (full capacity) | Yes (doubles fleet) | Terminate new ASG (fast) | Production, zero-risk deploys |
| Blue/Green (swap URL) | No | Yes (full new env) | Swap URL back (instant) | Critical production, major releases |
All at Once deploys the new version to every instance simultaneously. Every instance is taken out of service, updated, and brought back. This causes a brief outage equal to your application startup time. For a Spring Boot app this is typically 20-40 seconds. Only use this for development environments.
Rolling deploys to one batch of instances at a time (default batch size: 30%). During deployment, you are running at reduced capacity. For a 6-instance fleet with 30% batch size, Beanstalk updates 2 instances at a time, so you always have at least 4 healthy instances. The trade-off is that both old and new versions serve traffic simultaneously during the rollout.
Rolling with additional batch launches one extra batch of new instances before starting the rolling update. This maintains 100% of your normal capacity throughout the deployment. The extra instances are terminated after the deployment completes. This is the recommended policy for most production web tiers.
Immutable launches a completely new Auto Scaling group with the new version. Once all new instances pass health checks, Beanstalk moves them to the original ASG and terminates the old instances. This doubles your fleet cost during deployment but provides the fastest, safest rollback — just terminate the new ASG. Combined with Beanstalk's health checks, immutable deployments ensure traffic never switches to the new version unless it is fully healthy.
Blue/Green is not a single-environment policy but an environment-swap strategy. You maintain two complete environments (blue = current, green = new), deploy to green, run smoke tests, then call eb swap to atomically exchange the CNAME DNS records. Rollback is a second swap call — instant at the DNS level.
# Set deployment policy via EB CLI
eb deploy my-app-prod --staged
# Or configure in .ebextensions:
# .ebextensions/deployment.config
option_settings:
aws:elasticbeanstalk:command:
DeploymentPolicy: RollingWithAdditionalBatch
BatchSizeType: Fixed
BatchSize: "2"
Timeout: "600"
IgnoreHealthCheck: "false"
aws:elasticbeanstalk:healthreporting:system:
SystemType: enhanced
# Blue/Green: create green env, deploy, swap
eb create my-app-green \
--cname my-app-green \
--template my-app-prod
eb deploy my-app-green
# Run smoke tests against green URL...
# Swap CNAMEs (atomic, no DNS propagation needed — Beanstalk manages Route 53)
eb swap my-app-prod --destination_name my-app-green
# Rollback if needed
eb swap my-app-prod --destination_name my-app-green
/). For Spring Boot apps, configure the health check path to /actuator/health and ensure it returns fast (<3 seconds). A slow health endpoint will stall rolling deployments.
Environment Variables and Secrets Manager Integration
Beanstalk environment variables are injected as OS environment variables into every instance. You can set them via the console, EB CLI, or .ebextensions. Never commit secrets to .ebextensions files — use AWS Secrets Manager or SSM Parameter Store instead.
# Set environment variables via EB CLI
eb setenv \
SPRING_PROFILES_ACTIVE=prod \
DB_PASSWORD=CHANGE_ME \
REDIS_HOST=my-cache.abc.cfg.use1.cache.amazonaws.com
# List current environment variables
eb printenv my-app-prod
# Unset a variable
eb setenv MY_VAR= my-app-prod
For secrets, the recommended pattern is to store values in AWS Secrets Manager and retrieve them in a startup hook or directly in your Spring Boot app using the AWS SDK or the Spring Cloud AWS Secrets Manager starter.
# .ebextensions/06-secrets.config
# Retrieve a secret from SSM Parameter Store at instance startup
# and export it as an environment variable for the app
files:
"/opt/elasticbeanstalk/hooks/appdeploy/pre/00-fetch-secrets.sh":
mode: "000755"
owner: root
group: root
content: |
#!/bin/bash
export AWS_DEFAULT_REGION=us-east-1
DB_PASS=$(aws ssm get-parameter \
--name "/myapp/prod/db_password" \
--with-decryption \
--query "Parameter.Value" \
--output text)
# Inject into the EB environment
/opt/elasticbeanstalk/bin/get-config environment \
| jq --arg p "$DB_PASS" '. + {DB_PASSWORD: $p}' > /tmp/env.json
# Write to a sourced file
echo "export DB_PASSWORD=\"$DB_PASS\"" >> /etc/profile.d/app-secrets.sh
chmod 600 /etc/profile.d/app-secrets.sh
For Spring Boot, the cleanest approach is Spring Cloud AWS Secrets Manager, which auto-populates @Value annotations from Secrets Manager at application startup:
# src/main/resources/application-prod.properties
spring.config.import=aws-secretsmanager:/myapp/prod/db-credentials
# Beanstalk's instance IAM role must have secretsmanager:GetSecretValue
# src/main/resources/application.properties
spring.datasource.url=jdbc:postgresql://${DB_HOST}:5432/${DB_NAME}
spring.datasource.username=${db.username} # injected from Secrets Manager JSON key "username"
spring.datasource.password=${db.password} # injected from Secrets Manager JSON key "password"
<!-- pom.xml — Spring Cloud AWS Secrets Manager starter -->
<dependency>
<groupId>io.awspring.cloud</groupId>
<artifactId>spring-cloud-aws-starter-secrets-manager</artifactId>
<version>3.1.1</version>
</dependency>
aws-elasticbeanstalk-ec2-role IAM instance profile. Add an inline policy granting secretsmanager:GetSecretValue on the specific secret ARNs your application needs. Never grant secretsmanager:* on *.
RDS Integration: Coupled vs Decoupled Database
Elastic Beanstalk can provision an RDS instance as part of your environment (coupled) or you can connect to a separately-managed RDS instance (decoupled). The difference has major production implications.
Coupled RDS (configured in the Beanstalk console under Database settings) creates an RDS instance whose lifecycle is tied to the environment. If you delete or rebuild the environment, the RDS instance is deleted with it. Beanstalk automatically injects the connection details as environment variables: RDS_HOSTNAME, RDS_PORT, RDS_DB_NAME, RDS_USERNAME, RDS_PASSWORD. This is convenient for development but dangerous in production.
Decoupled RDS (strongly recommended for production) means your RDS cluster exists independently of Beanstalk. You create it with Terraform or the AWS Console, then pass the connection details as Beanstalk environment variables or via Secrets Manager. Terminating your Beanstalk environment has no effect on the database.
# Terraform: decoupled RDS Aurora Serverless v2 for production
resource "aws_rds_cluster" "app" {
cluster_identifier = "myapp-prod"
engine = "aurora-postgresql"
engine_version = "15.4"
engine_mode = "provisioned"
database_name = "myapp"
master_username = "appuser"
manage_master_user_password = true # Secrets Manager integration
serverlessv2_scaling_configuration {
min_capacity = 0.5
max_capacity = 8
}
vpc_security_group_ids = [aws_security_group.rds.id]
db_subnet_group_name = aws_db_subnet_group.main.name
skip_final_snapshot = false
deletion_protection = true
tags = { Environment = "prod" }
}
resource "aws_rds_cluster_instance" "app" {
cluster_identifier = aws_rds_cluster.app.id
instance_class = "db.serverless"
engine = aws_rds_cluster.app.engine
engine_version = aws_rds_cluster.app.engine_version
}
Pass the connection details to Beanstalk after provisioning:
eb setenv \
DB_HOST=$(terraform output -raw rds_endpoint) \
DB_NAME=myapp \
DB_PORT=5432 \
DB_SECRET_ARN=$(terraform output -raw rds_secret_arn) \
my-app-prod
Migration strategy when moving from coupled to decoupled RDS:
- Create a snapshot of the coupled RDS instance from the Beanstalk console.
- Restore the snapshot to a new standalone RDS cluster (outside Beanstalk).
- Update Beanstalk environment variables to point at the new cluster endpoint.
- Deploy and verify application connectivity.
- Remove the coupled database configuration from Beanstalk (this deletes the old coupled instance — your data is now on the standalone cluster).
Custom Platform Hooks: Procfile and Buildfile
Beyond .ebextensions, Beanstalk's Amazon Linux 2023 platforms support Procfile and Buildfile for controlling how the application is started and how the build is performed on the instance.
Procfile defines the process that Beanstalk should run. For Java, Beanstalk can run the JAR directly — but a Procfile lets you customise JVM flags, wrap the process with a custom script, or run multiple processes.
# Procfile (in project root, included in deployment ZIP)
web: java $JAVA_TOOL_OPTIONS -jar target/myapp.jar --server.port=8080
worker: java -jar target/myapp.jar --spring.profiles.active=worker
Buildfile specifies a build command that runs on the instance before the Procfile process is started. This is useful for compiled assets or on-instance Maven/Gradle builds (uncommon but supported).
# Buildfile (in project root)
build: ./scripts/build-assets.sh
Platform hooks are shell scripts placed in predefined hook directories. They run at specific lifecycle events and give you finer control than .ebextensions:
project-root/
├── .platform/
│ └── hooks/
│ ├── prebuild/ # Before application is built/staged
│ │ └── 01-set-timezone.sh
│ ├── predeploy/ # Before new version goes live (after staging)
│ │ └── 01-run-migrations.sh
│ └── postdeploy/ # After new version is live
│ └── 01-warm-cache.sh
#!/bin/bash
# .platform/hooks/predeploy/01-run-migrations.sh
# Only run on the first (leader) instance
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
INSTANCE_ID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/instance-id)
# Use a DynamoDB lock or SSM parameter to elect leader
LOCK=$(aws ssm put-parameter \
--name "/myapp/migration-lock" \
--value "$INSTANCE_ID" \
--type String \
--overwrite \
--query "Version" \
--output text 2>/dev/null || echo "locked")
if [ "$LOCK" = "locked" ]; then
echo "Migration already running on another instance, skipping."
exit 0
fi
cd /var/app/staging
java -jar target/myapp.jar --spring.profiles.active=migrate --spring.main.web-application-type=none
# Release lock
aws ssm delete-parameter --name "/myapp/migration-lock"
.platform/hooks/) are the modern AL2023 replacement for container_commands. They are shell scripts with proper exit code handling and run in a defined order. Use platform hooks for new AL2023 environments; continue using container_commands for AL2 compatibility.
CI/CD with CodePipeline and Terraform
A complete CI/CD pipeline for Elastic Beanstalk connects CodeCommit (or GitHub) → CodeBuild (build + test) → Elastic Beanstalk (deploy). CodePipeline orchestrates the stages and handles artifact storage in S3.
# terraform/codepipeline.tf
# S3 bucket for pipeline artifacts
resource "aws_s3_bucket" "pipeline_artifacts" {
bucket = "myapp-pipeline-artifacts-${data.aws_caller_identity.current.account_id}"
force_destroy = true
}
resource "aws_s3_bucket_versioning" "pipeline_artifacts" {
bucket = aws_s3_bucket.pipeline_artifacts.id
versioning_configuration { status = "Enabled" }
}
# CodeBuild project
resource "aws_codebuild_project" "build" {
name = "myapp-build"
service_role = aws_iam_role.codebuild.arn
build_timeout = 20
artifacts {
type = "CODEPIPELINE"
}
environment {
compute_type = "BUILD_GENERAL1_SMALL"
image = "aws/codebuild/standard:7.0"
type = "LINUX_CONTAINER"
image_pull_credentials_type = "CODEBUILD"
environment_variable {
name = "MAVEN_OPTS"
value = "-Xmx1024m"
}
}
source {
type = "CODEPIPELINE"
buildspec = "buildspec.yml"
}
}
# CodePipeline
resource "aws_codepipeline" "app" {
name = "myapp-prod-pipeline"
role_arn = aws_iam_role.codepipeline.arn
artifact_store {
location = aws_s3_bucket.pipeline_artifacts.bucket
type = "S3"
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
owner = "AWS"
provider = "CodeStarSourceConnection"
version = "1"
output_artifacts = ["source_output"]
configuration = {
ConnectionArn = aws_codestarconnections_connection.github.arn
FullRepositoryId = "myorg/myapp"
BranchName = "main"
DetectChanges = "true"
}
}
}
stage {
name = "Build"
action {
name = "Build"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
version = "1"
input_artifacts = ["source_output"]
output_artifacts = ["build_output"]
configuration = {
ProjectName = aws_codebuild_project.build.name
}
}
}
stage {
name = "Deploy"
action {
name = "Deploy"
category = "Deploy"
owner = "AWS"
provider = "ElasticBeanstalk"
version = "1"
input_artifacts = ["build_output"]
configuration = {
ApplicationName = "my-spring-boot-app"
EnvironmentName = "my-app-prod"
}
}
}
}
Your buildspec.yml compiles the JAR and packages it with .ebextensions and .platform directories:
# buildspec.yml (project root)
version: 0.2
phases:
install:
runtime-versions:
java: corretto21
pre_build:
commands:
- echo "Running tests..."
- ./mvnw test
build:
commands:
- echo "Building JAR..."
- ./mvnw package -DskipTests
- echo "Build completed: $(ls target/*.jar)"
post_build:
commands:
- echo "Packaging deployment bundle..."
- mkdir -p deploy
- cp target/myapp-*.jar deploy/myapp.jar
- cp -r .ebextensions deploy/ 2>/dev/null || true
- cp -r .platform deploy/ 2>/dev/null || true
- cp Procfile deploy/ 2>/dev/null || true
- cd deploy && zip -r ../myapp-deploy.zip .
artifacts:
files:
- myapp-deploy.zip
discard-paths: yes
cache:
paths:
- /root/.m2/**/*
Monitoring, Enhanced Health, and Managed Updates
Elastic Beanstalk has two health reporting modes: basic and enhanced. Enhanced health reporting (strongly recommended for production) installs the Beanstalk health agent on every instance, which reports application-level metrics — request counts, latency percentiles, HTTP status code distributions — in real time to the Beanstalk console and CloudWatch.
# .ebextensions/monitoring.config
option_settings:
aws:elasticbeanstalk:healthreporting:system:
SystemType: enhanced
HealthCheckSuccessThreshold: Ok
aws:elasticbeanstalk:cloudwatch:logs:
StreamLogs: true
DeleteOnTerminate: false
RetentionInDays: 30
aws:elasticbeanstalk:cloudwatch:logs:health:
HealthStreamingEnabled: true
DeleteOnTerminate: false
RetentionInDays: 7
# Custom CloudWatch alarm: p99 latency > 2s
aws:elasticbeanstalk:application:
Application Healthcheck URL: /actuator/health
Add custom CloudWatch alarms for your business metrics:
# CloudWatch alarm: p99 application latency > 2 seconds
aws cloudwatch put-metric-alarm \
--alarm-name "myapp-prod-p99-latency" \
--metric-name "InstancesOk" \
--namespace "AWS/ElasticBeanstalk" \
--dimensions Name=EnvironmentName,Value=my-app-prod \
--statistic Average \
--period 60 \
--threshold 2000 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 3 \
--alarm-actions arn:aws:sns:us-east-1:123456789:myapp-alerts
# Enhanced health dashboard via EB CLI
eb health my-app-prod --refresh
Managed Platform Updates automatically apply minor and patch platform updates to your environment during a weekly maintenance window. You set the window; Beanstalk applies the update using an immutable deployment to avoid downtime.
# .ebextensions/managed-updates.config
option_settings:
aws:elasticbeanstalk:managedactions:
ManagedActionsEnabled: true
PreferredStartTime: "Sun:04:00" # UTC
aws:elasticbeanstalk:managedactions:platformupdate:
UpdateLevel: minor # "patch" or "minor"
InstanceRefreshEnabled: true
Enhanced health introduces Beanstalk-specific health colours: Green (all OK), Yellow (degraded — some requests failing or high latency), Red (severely degraded — many requests failing), and Grey (no data). When an environment goes Yellow during a rolling deployment, Beanstalk halts the deployment and waits for you to investigate. This automatic deployment brake has saved countless production incidents.
# View enhanced health breakdown
eb health my-app-prod
# Environment my-app-prod Health Green
# Stats p99 p90 p75 p50 Requests 2xx 4xx 5xx
# Duration 120ms 85ms 62ms 41ms 4200 98.2% 1.5% 0.3%
#
# Instance ID State Health CPUUser Requests Last Deploy
# i-0abc123def456789 InService Ok 22% 1400 17m
# i-0def456abc123789 InService Ok 19% 1400 17m
# i-0123abc789def456 InService Ok 24% 1400 17m
Frequently Asked Questions
Elastic Beanstalk itself has no service charge. You pay only for the underlying AWS resources it provisions: EC2 instances, ALB, data transfer, RDS, etc. The cost profile is identical to provisioning those resources yourself, making Beanstalk purely a management convenience layer.
Yes. The Docker platform branch runs a single container defined by a Dockerrun.aws.json v1 file or a standard Dockerfile. For multi-container applications (an app server + a Redis sidecar, for example), Beanstalk supports the Multi-container Docker platform using Dockerrun.aws.json v2, which uses ECS under the hood. However, for serious multi-container workloads, migrating to standalone ECS is usually cleaner.
Use the Worker tier. A Worker environment runs your application alongside a daemon that polls an SQS queue. When a message arrives, the daemon makes an HTTP POST to http://localhost/ (or a configurable path) with the message body. Your app processes it and returns HTTP 200 to acknowledge. The SQS visibility timeout and dead-letter queue are configured in .ebextensions under aws:elasticbeanstalk:sqsd: option settings.
Yes. Configure the environment to use internal ALB (aws:elb:loadbalancer: CrossZone: true + set scheme to internal) and place EC2 instances in private subnets. Instances need NAT Gateway access to reach the Elastic Beanstalk service endpoints, S3 (for artifacts), and Systems Manager. Alternatively, use VPC Interface Endpoints for all these services to avoid NAT costs entirely.
Use eb ssh to connect and run sudo systemctl restart web, or use the "Restart App Server" action in the Beanstalk console. For a rolling restart (instance by instance), use eb restart from the EB CLI — this performs a rolling instance replacement using the current application version, which restarts the JVM without requiring a new artifact upload.