Deploying a web application involves more than just writing code; it requires managing servers, load balancers, and scaling policies. AWS Elastic Beanstalk simplifies this by providing a managed service that handles the infrastructure while you focus on the Python logic. This guide walks you through the process of preparing a Flask application for production and deploying it using the Elastic Beanstalk Command Line Interface (EB CLI).
Project Environment Setup
Before writing the application, you need a clean environment. AWS Elastic Beanstalk expects specific configurations to identify your application entry point and its dependencies. We will start by creating a project directory and a virtual environment to isolate our packages.
mkdir flask-aws-deploy
cd flask-aws-deploy
python3 -m venv venv
source venv/bin/activate
Once the virtual environment is active, install Flask and Gunicorn. Flask is our web framework, and Gunicorn is a WSGI HTTP Server. You should never use Flask's built-in development server in a production environment because it is not designed for security or high concurrency.
pip install flask gunicorn
pip freeze > requirements.txt
The requirements.txt file is mandatory. When you deploy, Elastic Beanstalk reads this file to install the necessary libraries on the Amazon Linux EC2 instances. If a package is missing from this file, your deployment will fail with an ImportError.
⚠️ Note: Ensure yourrequirements.txtincludesgunicorn. While your local machine might run fine without it usingflask run, the AWS environment uses Gunicorn to serve the application to the public internet.
Creating the Flask Application
Elastic Beanstalk's Python platform has a default configuration that looks for a file named application.py. It also expects the Flask object inside that file to be named application rather than the standard app. Following these naming conventions reduces the amount of manual configuration required later.
from flask import Flask, jsonify
# Elastic Beanstalk looks for a variable named 'application'
application = Flask(__name__)
@application.route("/")
def index():
return jsonify(
status="success",
message="Flask application is running on AWS Elastic Beanstalk",
version="1.0.0"
)
@application.route("/health")
def health_check():
# This endpoint is used by the Load Balancer to check if the app is alive
return jsonify(status="healthy"), 200
if __name__ == "__main__":
# Setting debug=True is helpful for local development
# but AWS will ignore this block when running via WSGI
application.run(host="0.0.0.0", port=5000, debug=True)
The /health route is a best practice for cloud deployments. AWS Application Load Balancers (ALB) perform periodic requests to your instances to ensure they are responding correctly. If the load balancer receives a 200 OK response, it keeps the instance in the rotation; otherwise, it marks it as unhealthy and stops sending traffic to it.
After saving this file, you can verify it works locally by running the script. You should see a JSON response when visiting the local URL in your browser.
python application.py
Expected output: * Running on http://0.0.0.0:5000. If you visit that URL, you should see the JSON status message defined in the index route.
Configuring the Deployment Environment
While Elastic Beanstalk can guess many settings, providing an explicit configuration ensures your application scales and behaves correctly. We use a directory named .ebextensions to store configuration files that AWS reads during the deployment process.
mkdir .ebextensions
touch .ebextensions/python.config
Inside python.config, we define the path to our WSGI application. This tells the server exactly where the Flask object is located. This step is critical if you decide to name your file something other than application.py or your object something other than application.
option_settings:
aws:elasticbeanstalk:container:python:
WSGIPath: application:application
aws:elasticbeanstalk:environment:proxy:staticfiles:
/static: static
The WSGIPath value application:application follows the pattern filename:objectname. The second section for staticfiles tells AWS to serve files from a directory named static directly through Nginx, which is much faster than routing those requests through the Python application.
⚠️ Note: YAML files are sensitive to indentation. Ensure you use two spaces for each indentation level and no tabs, or the AWS parser will reject the configuration file.
Initializing the Elastic Beanstalk CLI
You need the EB CLI installed on your local machine. If you haven't installed it yet, use pip install awsebcli. You also need AWS credentials configured via the AWS CLI or environment variables. Run the initialization command to link your local directory to an AWS application.
eb init -p python-3.12 flask-aws-app
During this process, the CLI will ask you several questions. Select your preferred region (e.g., us-east-1). If it asks about SSH, choose "Yes" if you want to be able to log into the EC2 instances directly for debugging, though it is not strictly required for the deployment to work.
After initialization, your project folder will contain a .elasticbeanstalk directory. This directory stores your project settings and should not be deleted. Now, create the environment and deploy the code. This step creates the actual AWS resources, including the EC2 instances, Security Groups, and CloudWatch logs.
eb create flask-env
This command will take 3-5 minutes to complete. The CLI provides real-time updates on the creation of each resource. You will see events related to the creation of the S3 bucket, the Load Balancer, and the Auto Scaling Group.
Expected terminal output during creation:
INFO: createEnvironment is starting.
INFO: Using elasticbeanstalk-us-east-1-1234567890 as Amazon S3 storage bucket for environment data.
INFO: Created target group named: eb-t-flask-env
INFO: Created load balancer named: awseb-e-m-AWSEBLoa-12345
INFO: Environment health has transitioned from Pending to Ok.
INFO: Successfully launched environment: flask-env
Verifying the Deployment
Once the eb create command finishes, your application is live on the internet. You can find the public URL by running a simple command that opens your default browser to the application's address.
eb open
If you prefer to see the status in the terminal, use the status command. This shows the health of the environment, the platform version being used, and the CNAME (URL) of the load balancer.
eb status
If the application shows a "502 Bad Gateway" or "Internal Server Error," the first place to look is the application logs. Elastic Beanstalk makes it easy to retrieve the last 100 lines of the web server logs directly in your terminal.
eb logs
Look specifically for Python tracebacks or Gunicorn errors. A common error is a missing dependency in requirements.txt or a syntax error in application.py that prevents the WSGI server from starting.
⚠️ Note: If your app requires environment variables (like database URLs or API keys), do not hardcode them. Use the EB CLI to set them securely:eb setenv KEY=VALUE. These are then accessible in Python viaos.environ.get('KEY').
Updating the Application
When you make changes to your code, you don't need to run eb create again. Instead, you commit your changes to Git (if you are using it) or simply run the deploy command. The EB CLI packages your updated code, uploads it to S3, and performs a rolling update on your EC2 instances.
# Make a change to application.py, then:
eb deploy
Elastic Beanstalk handles the update without downtime by updating instances in small batches. It ensures that at least some instances are always available to handle incoming traffic while others are being updated with the new code version.
Cleaning Up Resources
AWS charges for the resources used by Elastic Beanstalk, including the EC2 instances and the Load Balancer. To avoid unexpected costs when you are finished with this tutorial, delete the environment. This command removes all resources created by eb create.
eb terminate flask-env
The CLI will ask you to type the environment name to confirm the deletion. This process takes a few minutes as AWS tears down the networking and compute resources.
You have successfully built a production-ready Flask application and deployed it to a managed cloud environment. We covered the necessary file structure, the importance of the application naming convention, and how to use the EB CLI to manage the lifecycle of your app. For next steps, consider adding a database like Amazon RDS or setting up a CI/CD pipeline using GitHub Actions to automate the eb deploy command whenever you push to your main branch.