Deploy Python Apps with Elastic Beanstalk

Use AWS Elastic Beanstalk for Python apps — AWS Cloud & DevOps with Python.

Focus: use aws elastic beanstalk for python apps

Sponsored

Have you ever dreaded deploying a Python web app — wrestling with EC2 instances, SSH sessions, and nginx configs, only to break production at 2 AM? You’re not alone. AWS Elastic Beanstalk exists to kill that pain: it takes your Python code and automates the entire deployment — EC2 provisioning, load balancing, auto scaling, health monitoring, and even rolling updates — so you can focus on writing code instead of babysitting infrastructure. In this lesson, you’ll not only understand how Elastic Beanstalk works but also deploy a real Python Flask app in minutes, then learn how it compares to alternatives like EC2, ECS, and Lambda.

The problem this lesson solves

Traditional deployment for a Python app on AWS often looks like this: you launch an EC2 instance, SSH in, install Python, pip install your dependencies, copy your code with SCP or git, configure a WSGI server like Gunicorn, set up nginx as a reverse proxy, then pray the instance doesn’t die. If traffic spikes, you manually launch another instance and configure a load balancer. If the instance crashes, you start over. This manual approach is brittle, time-consuming, and prone to human error.

Elastic Beanstalk solves this by being a PaaS (Platform as a Service) layer on top of EC2, Auto Scaling, Elastic Load Balancing, and health monitoring. You provide your code, and Beanstalk builds the underlying infrastructure automatically — with sensible defaults and the ability to customize when needed. It’s the sweet spot between full control (EC2) and zero control (Lambda).

By the end of this lesson, you’ll be able to use AWS Elastic Beanstalk for Python apps confidently, from a simple Flask app to a production-ready deployment with environment variables, rolling updates, and monitoring.

Core concept / mental model

Think of Elastic Beanstalk like a recipe for your infrastructure. Just as a recipe turns ingredients (flour, eggs, sugar) into a cake without you knowing the oven’s internal wiring, Beanstalk turns your application code into a running web service without you managing each EC2 instance. The platform (Python 3.11, for example) is the “kitchen” — preconfigured with the right runtime, web server, and operating system.

Here’s a diagram in words: your code is uploaded to Beanstalk, which uploads it to an S3 bucket, then creates or updates an Auto Scaling group of EC2 instances. Each instance runs the platform’s web server (nginx) that proxies to Gunicorn, which runs your Python WSGI app. A load balancer distributes traffic. The health monitoring system checks HTTP responses and instance status, and the environment — a collection of these resources — is what you actually manage.

Key concepts to remember: - Application: a logical container for your project (can have multiple versions). - Environment: a running deployment of one application version, with its own resources and configuration. - Platform: the combination of operating system, runtime, and web server (e.g., Python 3.11 on Amazon Linux 2023). - Environment tier: Web server (for HTTP) or worker (for background jobs).

Everything is configurable via eb CLI, AWS Console, or configuration files (.ebextensions), but the magic is that you don’t need to touch any of it for a basic deployment.

How it works step by step

Deploying with Elastic Beanstalk follows a logical flow. Let’s break it down:

  1. Prepare your project: Ensure your Python app is structured as a WSGI/ASGI application (e.g., Flask or Django). Include a requirements.txt file with all dependencies.
  2. Initialize Beanstalk: In your project folder, run eb init to link your local code with an Elastic Beanstalk application. This creates a .elasticbeanstalk/ directory with configuration.
  3. Create an environment: Run eb create to provision all the necessary AWS resources. This takes several minutes — Beanstalk creates the EC2 instances, load balancer, security groups, and DNS name.
  4. Deploy code: Once the environment exists, use eb deploy to push new versions. Beanstalk stages your code in S3, then updates the instances.
  5. Monitor and scale: Use eb status or the Console to view health, logs, and events. Auto Scaling rules adjust capacity automatically based on CPU or latency.
  6. Customize (if needed): Add environment variables via eb setenv, or use .ebextensions config files to install packages or tweak server settings.

Each step builds on the previous one. The happy path uses nearly zero configuration, but as you grow, you’ll use configuration files and environment settings to control behavior.

Hands-on walkthrough

Let’s actually use AWS Elastic Beanstalk for Python apps with a minimal Flask app. You’ll need the AWS CLI configured and the EB CLI installed: pip install awsebcli (or eb standalone).

Step 1: Create a Flask app

Create a directory eb-python-demo with this simple application.py:

from flask import Flask

# Explicitly name the WSGI entry point for Beanstalk
application = Flask(__name__)

@application.route("/")
def hello():
    return "Hello, Elastic Beanstalk!"

if __name__ == "__main__":
    application.run(host="0.0.0.0", port=5000)

Also add requirements.txt:

flask==3.0.0

Important: Beanstalk expects your app to be importable as a WSGI module. The default entry point varies by platform — for Python on Amazon Linux, it looks for application.py (or app.py) unless you specify WSGIPath in .ebextensions or via settings.

Step 2: Initialize and create an environment

Now run these commands:

cd eb-python-demo
eb init -p python-3.11 --region us-east-1 demo-app
eb create demo-env --single --nlb
  • -p python-3.11 selects the Python 3.11 platform (check available with eb platform list).
  • --single forces a single instance (free tier friendly), avoiding a load balancer.
  • --nlb uses Network Load Balancer if you ever scale out; for single instance it’s harmless but can be omitted.

Expected output (shortened):

Creating application version archive "app-2023-12-01_..."
Environment: demo-env
Health: Green

After a few minutes, your app is live. Get the URL with eb status and open it in your browser:

eb status

Output contains CNAME: demo-env.us-east-1.elasticbeanstalk.com — visit it, and you’ll see “Hello, Elastic Beanstalk!”.

Step 3: Deploy a change

Update your Flask app to show a time and redeploy:

from flask import Flask
from datetime import datetime

application = Flask(__name__)

@application.route("/")
def hello():
    return f"Hello! The current time is {datetime.now().isoformat()}"

if __name__ == "__main__":
    application.run(host="0.0.0.0", port=5000)

Then run:

eb deploy

Beanstalk performs a rolling update (if you have multiple instances) or a simple restart. Your URL now shows the updated message.

Step 4: Manage environment variables

Add your DB credentials or API keys with:

eb setenv SECRET_KEY=your-secret-key MODE=prod

The variables are injected into the instance environment. In your app, read them via os.environ.

Compare options / when to choose what

Elastic Beanstalk isn’t the only way to deploy Python on AWS. Here’s a quick comparison to help you decide:

Option Control Setup speed Scaling Best for
Elastic Beanstalk Medium Fast Auto Monolithic web apps, quick deploys
EC2 (manual) High Slow Manual Full control, legacy apps
ECS / Fargate High Medium Auto Microservices, containers
Lambda Low Fast Auto Event-driven, serverless
AWS App Runner Low Fast Auto Simple containerized web apps

When to choose Elastic Beanstalk: - You have a traditional web app (Django, Flask) and want deployment automation without diving into containers. - You need to scale from a single instance to many without rewriting your app. - You want to manage infrastructure visually, with the ability to later migrate to ECS if you outgrow it.

When to avoid it: - Your app is a lightweight API with unpredictable traffic — Lambda might be cheaper. - You already have Docker containers and want fine-grained control — ECS or EKS is better. - You need stateful services (like databases) on the same instance — Beanstalk supports attaching RDS, but it’s easier to decouple.

Variations: - Use eb create --tier worker for background workers (e.g., Celery). - Enable rolling updates and batch size in the Console to minimize downtime. - Use dockerrun.aws.json with Docker platforms if you need custom runtimes.

Troubleshooting & edge cases

Even with Beanstalk’s magic, things can go wrong. Here are common problems and fixes:

“Failed to deploy application” with 500 error

Cause: Gunicorn can’t import your app. Check logs at /var/log/eb-engine.log. Fix: Ensure your WSGI file is named application.py or set WSGIPath in .ebextensions/options.config:

option_settings:
  aws:elasticbeanstalk:container:python:
    WSGIPath: app.py

“ModuleNotFoundError: No module named 'flask'”

Cause: Dependencies not listed or pip install failed. Fix: Verify requirements.txt exists and lists packages. Use eb logs to check /var/log/eb-engine.log for pip errors.

Environment health turns Red after eb setenv

Cause: An environment variable broke your app (e.g., you set PORT incorrectly). Fix: Check the app’s logs via eb logs. Use eb setenv --remove VARNAME to unset the offending variable.

Expected response is “403” but your app should be public

Cause: Security group restrictions or nginx config. Fix: By default, Beanstalk opens port 80. If you used a custom nginx config, verify it passes all requests to Gunicorn.

Port conflict on single instance

Cause: Your app listens on port 5000, but nginx expects it on 8080 (default). Fix: Don’t hardcode the port; use os.environ.get('PORT', 8080) and let Gunicorn bind to 0.0.0.0:8080.

Pro tip: Always check /var/log/eb-engine.log and /var/log/nginx/error.log first. They contain 90% of answers for deployment failures.

What you learned & what's next

You now understand how to use AWS Elastic Beanstalk for Python apps — from the mental model of PaaS to hands-on deployment of a Flask app, comparing it to other AWS compute options, and troubleshooting common issues. You’ve mastered the core objectives: the idea behind Beanstalk (automated infrastructure) and a practical exercise (deploying and updating an app).

Next step in this track: Continuous Integration / Continuous Delivery (CI/CD) — you’ll learn how to automate deployments to Elastic Beanstalk using AWS CodePipeline and GitHub Actions. That will turn your manual eb deploy into a fully automated pipeline. See you there!

Key takeaways

  • Elastic Beanstalk is a PaaS that automates EC2, load balancing, auto scaling, and health monitoring for your Python apps.
  • The eb CLI simplifies everything: eb init, eb create, eb deploy, eb status.
  • Your app must be WSGI-compatible; use application.py or set WSGIPath in .ebextensions.
  • Use eb setenv for environment variables; logs are your best friend in troubleshooting.
  • Compare Beanstalk with ECS, Lambda, and EC2 to pick the right level of control.
  • After mastering deployment, move to CI/CD to automate the entire process.

Practice recap

Now that you’ve deployed a basic Flask app, extend it: add a /health route that checks a database connection (like SQLite), set an environment variable DB_PATH via eb setenv, and redeploy. Monitor the health URL and watch your environment turn Green. Then try deleting the environment (eb terminate) and recreate it to see how reproducible it is.

Common mistakes

  • Forgetting to rename your WSGI file to application.py — Beanstalk looks for that by default; use WSGIPath in .ebextensions if you use a different name.
  • Hardcoding the port inside your app — Beanstalk expects Gunicorn to listen on port 8080; use os.environ.get('PORT', 8080) instead.
  • Skipping dependency pinning: a requirements.txt without version pins can cause a future deploy to break when a package updates.
  • Not checking eb logs first when the environment turns red — the answer is almost always in /var/log/eb-engine.log.
  • Using --single when you later need redundancy — you can promote to a load-balanced environment, but it’s easier to start with multiple instances from day one.

Variations

  1. Use the AWS Console to create and manage Elastic Beanstalk environments instead of the CLI — it’s slower but visually clear.
  2. Combine Beanstalk with Docker by creating a Dockerrun.aws.json (or using a Docker platform) for custom runtimes, like Python 3.12 before Beanstalk adds it.
  3. Use .ebextensions configuration files to install system packages or tweak nginx — treated as equivalent to manual server config.

Real-world use cases

  • Deploying a Django e-commerce site with a managed database (RDS) — Beanstalk handles web serving, Auto Scaling, and health checks while you focus on business logic.
  • Running a Flask REST API for a mobile app backend: use Elastic Beanstalk to scale from a single instance in dev to multiple behind a load balancer in production.
  • Holding a simple internal data dashboard for a small team: deploy a Flask app with no load balancer to keep costs near zero, but still get automated deployments.

Key takeaways

  • Elastic Beanstalk automates infrastructure for Python web apps: provisioning, deployment, scaling, and monitoring.
  • Start with eb init, then eb create; your app is live in minutes with zero manual server setup.
  • Keep your app WSGI-compatible and list all dependencies in requirements.txt to avoid import errors.
  • Use eb setenv for environment variables and eb logs for troubleshooting.
  • Compare Beanstalk with ECS and Lambda to pick the right tool for your architecture.
  • After deployment, automate with CI/CD pipelines to push updates seamlessly.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.