Introduction to AWS Elastic Beanstalk
Deploying and managing web applications in the cloud involves a staggering number of moving parts: EC2 instances, load balancers, auto-scaling groups, security groups, S3 storage, monitoring alarms, and deployment pipelines. AWS Elastic Beanstalk abstracts away this complexity, giving developers a single, coherent platform to deploy applications with minimal friction. Think of it as a managed Platform-as-a-Service (PaaS) layer that sits on top of core AWS infrastructure services. You hand it your code, and Elastic Beanstalk handles the restāprovisioning resources, managing capacity, monitoring health, and even applying platform updates. This tutorial walks you through a complete setup and configuration journey, from installing the command-line tools to running a production-ready environment with custom configurations, database integration, and secure HTTPS endpoints.
What is AWS Elastic Beanstalk?
š Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →AWS Elastic Beanstalk is an orchestration service that automates the deployment of applications across the AWS infrastructure stack. It supports multiple platforms including Java, .NET, Node.js, Python, Ruby, Go, PHP, and Docker containers. When you provide your application codeāeither as a ZIP archive, a WAR file, or a Docker imageāElastic Beanstalk automatically creates an environment that includes:
- A load-balanced fleet of EC2 instances running your application
- Auto-scaling groups that scale capacity based on demand
- Security groups with sensible defaults
- Amazon S3 storage for application version archives
- Amazon CloudWatch monitoring dashboards and alarms
- Environment health checks and automatic recovery mechanisms
- Optional managed database instances (RDS)
The key insight is that you retain full control over every underlying resourceāyou can SSH into instances, tweak security groups, and customize CloudFormation templatesābut you don't have to manage any of it unless you want to. Elastic Beanstalk uses AWS CloudFormation under the hood to provision resources, which means you get all the benefits of infrastructure-as-code without writing a single CloudFormation template by hand.
Why Elastic Beanstalk Matters
For development teams, Elastic Beanstalk solves several critical pain points:
- Reduced operational overhead: Instead of configuring EC2, ELB, and Auto Scaling separately, you issue a single command and get a production-grade environment in minutes.
- Consistent environments across stages: You can replicate identical environments for development, staging, and production, eliminating "works on my machine" issues.
- Built-in deployment strategies: Elastic Beanstalk supports all-at-once, rolling, rolling-with-batch, and immutable deployments, plus blue/green deployments via environment swapping.
- Managed platform updates: When a new Amazon Linux AMI or language runtime version is released, Elastic Beanstalk can automatically apply it to your instances on a schedule you define.
- Zero-cost service: There is no additional charge for Elastic Beanstalk itselfāyou pay only for the underlying AWS resources your application consumes.
- Developer velocity: Teams spend time writing application code, not managing infrastructure, which directly accelerates time-to-market.
Core Concepts and Architecture
Before diving into the hands-on setup, it is important to understand the building blocks of Elastic Beanstalk:
- Application: A logical container for all the environments, versions, and configurations related to a single deployable project.
- Environment: A specific running instance of an application with its own set of resources (EC2 instances, load balancer, etc.). Environments can be web server environments (with an ELB) or worker environments (with an SQS queue).
- Application Version: A point-in-time snapshot of your deployable code, stored in S3 and associated with a version label.
- Environment Configuration: The settings that define how an environment behavesāinstance type, scaling parameters, environment variables, platform version, and VPC settings.
- Saved Configuration: A reusable template of environment settings that you can apply when creating new environments.
- Platform: The runtime stack (e.g., "Python 3.11 running on Amazon Linux 2023") that Elastic Beanstalk uses as the foundation for your instances.
Prerequisites
To follow this tutorial, you will need:
- An active AWS account with appropriate permissions (AdministratorAccess or a policy covering Elastic Beanstalk, EC2, S3, RDS, and IAM)
- The AWS CLI installed and configured (
aws configure) - The Elastic Beanstalk CLI (EB CLI) installed
- A sample application ready to deploy (we will use a simple Node.js app as an example)
- An existing VPC with public and private subnets (optional but recommended for production)
Complete Setup and Configuration Guide
Step 1: Installing the Elastic Beanstalk CLI
The EB CLI is a Python-based command-line tool that provides direct, scriptable access to Elastic Beanstalk operations. Install it using pip inside a virtual environment to avoid system-wide Python conflicts:
# Create and activate a virtual environment (recommended)
python3 -m venv eb-cli-venv
source eb-cli-venv/bin/activate
# Install the EB CLI via pip
pip install awsebcli
# Verify the installation
eb --version
# Expected output: EB CLI 3.20.x (Python 3.x)
# Deactivate the virtual environment when done
deactivate
Alternatively, you can install it globally, but the virtual environment approach keeps dependencies isolated. On macOS you can also use Homebrew: brew install awsebcli.
Step 2: Creating a Sample Application
Create a minimal Node.js application to use throughout this guide. This gives you a concrete, testable artifact to deploy:
# Create project directory and navigate into it
mkdir my-elasticbeanstalk-app
cd my-elasticbeanstalk-app
# Initialize a Node.js project
npm init -y
# Install Express as a dependency
npm install express
# Create the main application file
cat > app.js << 'EOF'
const express = require('express');
const app = express();
const PORT = process.env.PORT || 8080;
app.get('/', (req, res) => {
res.json({
status: 'healthy',
message: 'Elastic Beanstalk deployment successful!',
environment: process.env.ENVIRONMENT_NAME || 'unknown',
timestamp: new Date().toISOString()
});
});
app.get('/health', (req, res) => {
res.status(200).json({ status: 'ok' });
});
const server = app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
// Graceful shutdown handling
process.on('SIGTERM', () => {
console.log('SIGTERM received, shutting down gracefully');
server.close(() => process.exit(0));
});
EOF
# Create a Procfile (optional for Node.js but good practice)
cat > Procfile << 'EOF'
web: node app.js
EOF
The application listens on the port specified by the PORT environment variableāElastic Beanstalk sets this automatically for web server environments. The /health endpoint is useful for configuring custom health checks later.
Step 3: Initializing an Elastic Beanstalk Environment
Navigate to your project directory and run eb init to configure the application and its first environment. This interactive command sets up the connection between your local code and the Elastic Beanstalk service:
# Initialize Elastic Beanstalk for this project
eb init
# Interactive prompts (fill in as follows):
# Select a default region: [choose your preferred region, e.g., us-east-1]
# Select an application: [Create new application]
# Application name: my-elasticbeanstalk-app
# Select a platform: Node.js 18 (or the latest available)
# Select a platform branch: [default]
# Do you want to use CodeCommit? [N]
# Do you want to set up SSH for your instances? [Y]
# Select a keypair: [choose existing or create new]
Behind the scenes, eb init creates a hidden .elasticbeanstalk directory containing configuration files. The key file is config.yml, which stores your application name, default region, platform selection, and SSH keypair name. You can inspect it:
cat .elasticbeanstalk/config.yml
# Example output:
# branch-defaults:
# default:
# environment: null
# global:
# application_name: my-elasticbeanstalk-app
# default_ec2_keyname: my-keypair
# default_platform: Node.js 18
# default_region: us-east-1
Step 4: Creating Your First Environment
Now create a running environment. The eb create command provisions all resources and deploys your application in one step:
# Create a production-ready environment with a load balancer
eb create production-env
# Or create a simpler, single-instance environment for development
eb create dev-env --single
# Monitor the creation process
eb status
# Once complete, open the application in a browser
eb open
The environment creation process takes approximately 5ā10 minutes. During this time, Elastic Beanstalk provisions an EC2 instance, a security group, an Elastic Load Balancer (unless you used --single), and an Auto Scaling group, then uploads your application code and deploys it. You can watch the events stream with:
eb events --follow
Step 5: Deploying Application Updates
After making changes to your code, deploy updates with a single command. Elastic Beanstalk handles the deployment strategy based on your environment type:
# Stage and deploy all changes
eb deploy
# Deploy with a specific version label
eb deploy --version v1.2.0
# Deploy with a message for tracking
eb deploy --message "Added health check endpoint and error handling"
# List all deployed versions
eb list
# View detailed deployment information
eb status --verbose
By default, eb deploy creates a ZIP archive of your project (respecting .ebignore or .gitignore), uploads it to S3, creates a new application version, and triggers a deployment to your environment. The deployment strategy defaults to "all at once" for new environmentsāyou can change this later.
Step 6: Configuring Environment Properties and Variables
Environment variables are the primary way to inject configuration into your application without modifying code. Set them via the CLI or the Management Console:
# Set environment variables via CLI
eb setenv ENVIRONMENT_NAME=production DATABASE_URL=postgres://localhost:5432/mydb LOG_LEVEL=info
# View current environment variables
eb printenv
# Remove a specific variable
eb setenv DATABASE_URL= --delete
# Set multiple variables from a file
cat > env-vars.txt << 'EOF'
ENVIRONMENT_NAME=production
DATABASE_URL=postgres://db-host:5432/mydb
LOG_LEVEL=info
API_KEY=sk-123456789
EOF
eb setenv --file env-vars.txt
Environment variables are stored encrypted in the Elastic Beanstalk configuration and are available to your application process at runtime. For sensitive values like API keys and database passwords, consider using AWS Secrets Manager or SSM Parameter Store combined with IAM roles for retrieval at application startup, rather than plain environment variables.
Step 7: Customizing Environment Configuration with .ebextensions
For configurations beyond what the CLI exposes directly, Elastic Beanstalk uses .ebextensions configuration files written in YAML or JSON. These files allow you to customize every aspect of the underlying CloudFormation stack. Create a .ebextensions directory in your project root and add configuration files:
mkdir .ebextensions
cat > .ebextensions/01-instance-config.config << 'EOF'
option_settings:
aws:autoscaling:launchconfiguration:
InstanceType: t3.medium
EC2KeyName: my-keypair
IamInstanceProfile: aws-elasticbeanstalk-ec2-role
aws:autoscaling:asg:
MinSize: 2
MaxSize: 4
aws:elasticbeanstalk:application:
Application Healthcheck URL: /health
aws:elasticbeanstalk:environment:
EnvironmentType: LoadBalanced
LoadBalancerType: application
aws:ec2:vpc:
VPCId: vpc-0a1b2c3d4e5f6
Subnets: subnet-111,subnet-222
ELBSubnets: subnet-333,subnet-444
EOF
cat > .ebextensions/02-cloudwatch-logs.config << 'EOF'
packages:
yum:
awslogs: []
commands:
01_configure_awslogs:
command: |
cat > /etc/awslogs/awslogs.conf << 'AWSCONF'
[general]
state_file = /var/lib/awslogs/agent-state
[/var/log/eb-engine.log]
file = /var/log/eb-engine.log
log_group_name = `/aws/elasticbeanstalk/${AWSEBEnvironmentName}/eb-engine.log`
log_stream_name = {instance_id}
[/var/log/nginx/access.log]
file = /var/log/nginx/access.log
log_group_name = `/aws/elasticbeanstalk/${AWSEBEnvironmentName}/nginx-access.log`
log_stream_name = {instance_id}
AWSCONF
02_start_awslogs:
command: service awslogs start
EOF
Configuration files are processed in alphabetical order. The naming convention 01-xxx.config, 02-xxx.config ensures predictable execution order. The option_settings key maps directly to CloudFormation resource properties, giving you fine-grained control over instance types, scaling parameters, VPC placement, and health check URLs.
Step 8: Configuring Auto Scaling and Load Balancing
Production environments need proper scaling policies. Elastic Beanstalk supports multiple scaling options that you can configure through .ebextensions:
cat > .ebextensions/03-scaling.config << 'EOF'
option_settings:
aws:autoscaling:asg:
MinSize: 2
MaxSize: 10
CustomMin: 2
CustomMax: 10
aws:autoscaling:trigger:
MeasureName: TargetResponseTime
Statistic: Average
Unit: Seconds
Period: 300
EvaluationPeriods: 2
UpperThreshold: 3
LowerThreshold: 1
UpperBreachScaleIncrement: 2
LowerBreachScaleIncrement: -1
aws:elbv2:listener:default:
ListenerEnabled: true
Protocol: HTTP
Port: 80
aws:elasticbeanstalk:healthreporting:system:
SystemType: enhanced
HealthCheckSuccessThreshold: 3
ConfigDocument:
ApplicationHealthcheckEnabled: true
ApplicationHealthcheckURL: /health
ApplicationHealthcheckTimeoutSeconds: 5
EOF
This configuration establishes CPU-based scaling with thresholds that react to sustained load. The enhanced health reporting system provides detailed instance-level metrics and automatic recovery when instances fail health checks. For more sophisticated scaling, you can use step scaling policies or scheduled scaling actions via additional CloudFormation resources in your .ebextensions files.
Step 9: Integrating an RDS Database
Elastic Beanstalk can provision and manage an RDS database instance tied to your environment. However, for production workloads, it is strongly recommended to create the database independently and reference it via environment variables, so that environment termination does not accidentally delete your data:
# Create an RDS instance independently (recommended for production)
aws rds create-db-instance \
--db-instance-identifier myapp-postgres \
--db-instance-class db.t3.medium \
--engine postgres \
--engine-version 15.4 \
--master-username myappuser \
--master-user-password 'SecurePassw0rd!' \
--allocated-storage 20 \
--vpc-security-group-ids sg-0a1b2c3d4e5f6 \
--db-subnet-group-name my-db-subnet-group \
--publicly-accessible false
# Wait for the database to become available
aws rds describe-db-instances \
--db-instance-identifier myapp-postgres \
--query 'DBInstances[0].Endpoint.Address'
# Set the connection string as an environment variable in Elastic Beanstalk
eb setenv DATABASE_URL=postgres://myappuser:SecurePassw0rd!@myapp-postgres.xxxxx.us-east-1.rds.amazonaws.com:5432/mydb
If you do choose to let Elastic Beanstalk create the database, use the --database flag with eb create. But always enable snapshot retention and understand that the database lifecycle is tied to the environment unless you explicitly decouple it:
# Creating an environment with an integrated RDS database (development only)
eb create dev-with-db --database \
--database.instance db.t3.micro \
--database.storage 20 \
--database.user myappuser \
--database.pass 'SecurePassw0rd!'
Step 10: Configuring HTTPS and Custom Domains
Production applications must serve traffic over HTTPS. Elastic Beanstalk supports Application Load Balancers (ALB) with HTTPS listeners and ACM certificates. Here is how to configure it:
cat > .ebextensions/04-https-listener.config << 'EOF'
option_settings:
aws:elbv2:listener:443:
ListenerEnabled: true
Protocol: HTTPS
SSLCertificateArns: arn:aws:acm:us-east-1:123456789012:certificate/abc123-def456-ghi789
SSLPolicy: ELBSecurityPolicy-TLS13-1-2-2021-06
DefaultProcess: default
aws:elbv2:listener:443:default:
Protocol: HTTPS
Port: 443
Resources:
HttpListenerRedirect:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: redirect
RedirectConfig:
Protocol: HTTPS
Port: 443
Host: '#{host}'
Path: '/#{path}'
Query: '#{query}'
StatusCode: HTTP_301
LoadBalancerArn:
Ref: AWSEBLoadBalancer
Port: 80
Protocol: HTTP
EOF
Before applying this configuration, you must request an ACM certificate for your domain in the same region as your Elastic Beanstalk environment. Then update the SSLCertificateArns value with your certificate ARN. The included CloudFormation resource creates an HTTP-to-HTTPS redirect listener automatically.
For custom domains, create a CNAME or alias record in Route 53 pointing to your environment's load balancer endpoint:
# Get the environment's load balancer DNS name
eb status --verbose | grep -i "load.*balancer.*dns"
# Create a Route 53 alias record (via AWS CLI)
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch '{
"Changes": [{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "app.example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z35HXDROA1ZABC",
"DNSName": "myapp-env-123.us-east-1.elb.amazonaws.com",
"EvaluateTargetHealth": true
}
}
}]
}'
Step 11: Configuring Deployment Strategies
Elastic Beanstalk offers several deployment strategies that trade off speed against safety. Configure your preferred strategy through the CLI or configuration files:
# Set immutable deployment (safest option)
eb deploy --strategy immutable
# Set rolling deployment with batch size
eb deploy --strategy rolling --batch-size 25
# Set rolling with additional batch (extra safety)
eb deploy --strategy rolling-with-batch --batch-size 30
# Store the deployment strategy in a saved configuration
eb config save --cfg-name production-config
Immutable deployments create an entirely new set of instances, redirect traffic, and then terminate the old instances. This approach eliminates the risk of in-place failures but temporarily doubles your instance count. Rolling deployments update instances in batches, keeping capacity online throughout the process. Choose the strategy that matches your application's tolerance for brief capacity reduction and your budget for temporary duplicate infrastructure.
Step 12: Enabling Managed Platform Updates
AWS regularly releases updated platform versions with security patches, new AMIs, and language runtime updates. Elastic Beanstalk can automatically apply these updates on a schedule you control:
cat > .ebextensions/05-managed-updates.config << 'EOF'
option_settings:
aws:elasticbeanstalk:managedactions:
ManagedActionsEnabled: true
PreferredStartTime: 'Sun:03:00'
aws:elasticbeanstalk:managedactions:platform:
UpdateLevel: minor
InstanceRefreshEnabled: true
EOF
This configuration enables managed platform updates every Sunday at 3 AM UTC, applying minor version updates automatically. Major version updates (e.g., Python 3.10 to 3.11) require explicit opt-in. The InstanceRefreshEnabled setting ensures that during an update, instances are replaced rather than patched in-place, maintaining immutable infrastructure principles.
Step 13: Setting Up Environment Cloning and Blue/Green Deployments
For zero-downtime major version upgrades or risky changes, use environment cloning to create a staging environment identical to production:
# Clone the production environment
eb clone production-env --name production-green
# Deploy the new version to the green environment
eb deploy production-green --version v2.0.0
# Run smoke tests against the green environment's URL
curl https://production-green.us-east-1.elasticbeanstalk.com/health
# Swap environment CNAMEs to promote green to production
eb swap production-env --destination_name production-green
# After verifying the swap, terminate the old environment
eb terminate production-env --force
Environment swapping exchanges the CNAME records between two environments, instantly redirecting traffic with no downtime. This is the foundation of blue/green deployments on Elastic Beanstalk. Always test the green environment thoroughly before initiating the swap.
Step 14: Monitoring, Logging, and Troubleshooting
Elastic Beanstalk integrates deeply with CloudWatch for metrics, logs, and alarms. Access logs and metrics through the EB CLI:
# View recent environment events
eb events --limit 20
# Tail environment logs in real time
eb logs --tail
# Download all logs for a specific instance
eb logs --instance i-0a1b2c3d4e5f6 --zip-output logs.zip
# View CloudWatch metrics for the environment
eb health --refresh
# SSH into an instance for deeper troubleshooting
eb ssh
# Once connected, check application logs:
sudo tail -f /var/log/eb-engine.log
sudo tail -f /var/log/nginx/access.log
Set up CloudWatch alarms for critical metrics to receive notifications when your environment experiences issues:
cat > .ebextensions/06-cloudwatch-alarms.config << 'EOF'
Resources:
HighCPUAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName:
Fn::Sub: "${AWSEBEnvironmentName}-HighCPU"
AlarmDescription: "CPU utilization exceeds 85% for 5 minutes"
Namespace: AWS/EC2
MetricName: CPUUtilization
Dimensions:
- Name: AutoScalingGroupName
Value:
Ref: AWSEBAutoScalingGroup
Statistic: Average
Period: 300
EvaluationPeriods: 1
Threshold: 85
ComparisonOperator: GreaterThanThreshold
AlarmActions:
- Ref: NotificationTopic
NotificationTopic:
Type: AWS::SNS::Topic
Properties:
TopicName:
Fn::Sub: "${AWSEBEnvironmentName}-Alerts"
Subscription:
- Endpoint: admin@example.com
Protocol: email
EOF
Best Practices for Elastic Beanstalk
- Treat environments as ephemeral: Never make manual changes to instances via SSH that would be lost on termination. All configuration should flow through
.ebextensions, environment variables, or deployment artifacts. - Decouple your database: Always create RDS instances independently and reference them via environment variables. This prevents accidental data loss when environments are terminated or rebuilt.
- Use
.ebignorefiles: Create an.ebignorefile to exclude unnecessary files from deployment archives (node_modules, .git directory, test files). This reduces upload size and speeds deployments. - Version your application artifacts: Use meaningful version labels (e.g., git commit SHA or semantic version) to make rollbacks straightforward and auditable.
- Enable enhanced health monitoring: The enhanced health engine provides more granular metrics and faster detection of failed instances compared to basic health reporting.
- Use immutable deployments for production: Immutable deployments eliminate the risk of failed in-place updates and provide a clean rollback path.
- Store sensitive configuration in AWS Secrets Manager: For API keys, database credentials, and other secrets, retrieve them at runtime using the AWS SDK rather than hardcoding them in environment variables.
- Implement graceful shutdown handling: Ensure your application responds to SIGTERM signals and drains connections properly. Elastic Beanstalk sends SIGTERM before terminating instances during scaling and deployments.
- Tag your resources: Use the
aws:elasticbeanstalk:application:tagsoption setting to propagate tags to all resources created by your environment for cost allocation and governance. - Test
.ebextensionschanges in a staging environment first: Configuration file errors can prevent environment creation or updates. Always validate changes in a non-production environment before applying to production.
Conclusion
AWS Elastic Beanstalk occupies a powerful middle ground in the cloud deployment landscapeāit provides enough abstraction to eliminate infrastructure toil while preserving enough control to handle complex production requirements. Through this guide, you have walked through a complete journey: installing the CLI, creating a sample application, provisioning environments, configuring auto-scaling, integrating databases, enabling HTTPS, setting up managed updates, and establishing deployment pipelines with blue/green strategies. The combination of the EB CLI for rapid iteration and .ebextensions for deep customization gives you a platform that grows with your application's needs. As your architecture evolves, Elastic Beanstalk integrates naturally with other AWS servicesāyou can add CloudFront CDN distributions, connect ElastiCache clusters, or route traffic through API Gateway, all while Elastic Beanstalk continues to handle the core compute and deployment concerns. The result is a development experience where infrastructure fades into the background, letting you focus on the code that delivers value to your users.