Skip to content

How to Automate a Python Flask App Deployment with AWS Elastic Beanstalk

December 7, 2023

Onkar Singh

The following tutorial will guide development users on automating the deployment of a Python API. We chose AWS Elastic Beanstalk as our deployment tool. The 3 main points are:

  1. Deploy a Python Flask App with AWS Elastic Beanstalk
  2. Automate SSL Certificate Installation and renewal
  3. Automate nginx config updates to prevent “Payload Too Large” 413 HTTP error codes

#2 and #3 enable a minimum possible downtime for the web service. High level knowledge of AWS services is recommended for this tutorial.

Table of Contents:

  1. Why Elastic Beanstalk?
  2. Sample App
  3. Deployment to Elastic Beanstalk (EB)
  4. Automate SSL Certificate Installation and Renewal
  5. Automate nginx Config Updates to Tackle “Payload Too Large” 413 HTTP Errors
  6. Conclusion
  7. References

Why Elastic Beanstalk?

Elastic Beanstalk is a beginner-friendly AWS service that allows developers to deploy web applications without a deep knowledge of the underlying AWS infrastructure.

Sample App

1. Install Python from https://www.python.org/downloads/

2. For this tutorial, we will be using the sample flask app below:

from flask import Flask

application = Flask(__name__)

@application.route("/")
def hello():
    return "Welcome to Onkar's Sample Python Flask App"

if __name__ == "__main__":
    application.run(host='127.0.0.1', port=5000, debug=True)

3. Add another file to the project called requirements.txt, this file tells the EB environment that our app needs Flask v2.0.1 to run and allows dependency installation.

Flask==2.0.1

On localhost

4. Now, on your localhost, run the following command to install Flask and run the app in the project directory:

# Install Flask
pip install flask

# Run the python Flask Application locally
python ./application.py

5. Zip the project folder and name it “SampleApp.zip”. We’ll use this zipped file in the next steps.

Deployment to Elastic Beanstalk (EB)

1. Using the AWS Console, let’s create a new Elastic Beanstalk application.

a. Navigate to Elastic Beanstalk from the AWS Services Menu
b. Click the “Create Application” button. Now, you’ll see a form open.
c. Name your application. I’m calling mine – “Sample App Onkar”.
d. For the Platform option – choose “Python” and leave rest of the options as default.
e. For the Application Code option – choose “upload your own code” and upload SampleApp.zip
f. Hit “Create Application.”

 

Create Webserver

2. This would create the application as well as create a web server environment under our application.

3. The environment creation process takes about 5 minutes because it provisions all the resources required for an environment such as load balancers, security groups, EC2 instances, etc.

4. After the environment is created and shows a healthy status, the application should be available at the link shown on the environment page of the application. My env is hosted at http://sampleapponkar-env.eba-ffjmsc4p.us-east-1.elasticbeanstalk.com

Deploy

5. For subsequent deploys, upload the updated zipped project folder using the “Upload and Deploy” button on the specific environment page.

This was all for the deployment piece. You can look at logs, configuration, and monitoring on the environment page for debugging complex applications.

Automate SSL Certificate Installation and Renewal

To make your EB application easier to manage, you can automate the renewal of the EB domain’s SSL Certificate. Normally, SSL certificates are configured for domains you own. However, our EB environment URL is http://sampleapponkar-env.eba-ffjmsc4p.us-east-1.elasticbeanstalk.com/ and we don’t own the elasticbeanstalk.com domain.

Now, there are a few ways to install an SSL Certificate for an Elastic Beanstalk environment:

  1. Using the Application Load Balancer + ACM. However, having a load balancer on a single instance application might add unnecessary AWS costs just for enabling HTTPS.
  2. Using a CloudFront configuration. This is great for setting up CDN type content for satisfying global traffic.
  3. Install your own SSL certificate on the underlying EC2 instance. This process is a bit manual but the most cost-effective and suitable for single instance applications.

The following guide will walk you through Option #3 and how to implement automatic SSL cert renewals. For this to work, there must be a DNS mapping already set from your application’s Elastic beanstalk URL to your custom domain i.e. http://onkar.bluerelay.com pointing to http://sampleapponkar-env.eba-ffjmsc4p.us-east-1.elasticbeanstalk.com/. This method also does not incur additional costs. We used the popular option CertBot for generating SSL Certificates and ebextensions scripts for the generation and renewal process.

1. Create a folder called .ebextensions in the root directory of your folder.

2. Create a file called config and paste the following code into it:

container_commands:
    00_download_epel:
        command: "sudo wget -r --no-parent -A 'epel-release-*.rpm' http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/"
        ignoreErrors: true
    10_install_epel_release:
        command: "sudo rpm -Uvh dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-*.rpm"
        ignoreErrors: true
    20_enable_epel:
        command: "sudo yum-config-manager --enable epel*"
        ignoreErrors: true
    30_install_certbot:
        command: "sudo yum install -y certbot python2-certbot-nginx"
        ignoreErrors: true

This config file will install CertBot and its dependencies on the underlying EC2 instance.

3. Open port 443 on the EC2 instance by modifying the inbound rules of the associated security group. Create a file named 2_open_port_443.config with the following content:

Resources:
    sslSecurityGroupIngress:
        Type: AWS::EC2::SecurityGroupIngress
        Properties:
            GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
            IpProtocol: tcp
            ToPort: 443
            FromPort: 443
            CidrIp: 0.0.0.0/0

4. For the cert installation to trigger after the deployment is complete, we will use the postdeploy hook. This is the last hook to get triggered.

5. Create a folder called .platform in the project root directory.

  • Create a folder called hooks inside it.
  • Create another folder called postdeploy inside hooks.
  • The folder structure would be .platform/hooks/postdeploy

6. Create a file called sh inside postdeploy folder with the following content:

#!/usr/bin/env bash
sudo certbot -n -d YOUR_DOMAIN_NAME --nginx --agree-tos --email YOUR_EMAIL

Replace the domain name and email to the correct values. This command verifies if the host server on which the command runs on is pointing to the specified domain name. Once the domain is verified, it issues the SSL Certs and automatically places them in the correct nginx directory and updates the nginx configurations to use them. CertBot is truly awesome.

7. Now we need to grant executable permission to this script. For that create a file called config with the following:

container_commands:
    00_permission_hook:
        command: "chmod +x .platform/hooks/postdeploy/1_generate_certificate.sh"

8. Until this point, the certificate generation part will be handled, however, we also want to automate SSL Certificate renewal. For that, we’ll setup a cron job using a crontab. Create a file under .ebextensions called config with the following content:

files:
    /tmp/renew_ssl_cron:
        mode: "000777"
        owner: root
        group: root
        content: |
            0 3,15 * * * certbot renew --no-self-upgrade

container_commands:
    1_create_cert_crontab:
        command: "sudo crontab /tmp/renew_ssl_cron"
    2_delete_cronjob_file:
        command: "sudo  rm /tmp/renew_ssl_cron"
        ignoreErrors: true

We’re specifying a file which contains the cron expression and then later use container commands to create a crontab using that file and clean it up. This should set a schedule job to go off at 3am and 3pm daily to attempt to renew the certs.

Upload to EB

9. Now the project structure should look something like on left:

Now, zip the project and upload to EB.

10. To troubleshoot and monitor ebextensions scripts, you can check /var/log/cfn-init.log and /var/log/eb-hooks.log on the ec2 instance.

Automate nginx Config Updates to Tackle “Payload Too Large” 413 HTTP Errors

There might be some cases where the default EB configuration for nginx might not be sufficient. For example, by default nginx is configured to allow a max of 1MB request body with POST requests. Since the nginx configurations are overridden, every time a new application version is deployed, automating such a configuration update saves a lot of manual work after each deployment.

Automation

To change the max request body size to 20M, you need to update the /etc/nginx/nginx.conf file and add the line as show below:

To automate this process, we’ll add some more commands to our .ebextensions folder from the previous section.

1. Create a file called sh inside the postdeploy folder with the following content:

#!/usr/bin/env bash
sudo sed -i 's/client_header_timeout/client_max_body_size 20M;\n    client_header_timeout/g'  /etc/nginx/nginx.conf
sudo nginx -s reload
echo nginx config update complete

In the above script, we’re essentially using the sed command to replace any occurrence of the phrase

client_header_timeout

With

client_max_body_size 20M; client_header_timeout

and then it reloads the nginx configuration by calling nginx -s reload.

2. Also, modify config under .ebextensions folder to include exec permissions for filesize update script. The resultant 3_grant_exec_permission.config would be:

container_commands:
    00_permission_hook:
        command: "chmod +x .platform/hooks/postdeploy/1_generate_certificate.sh"
    01_permission_hook2:
        command: "chmod +x .platform/hooks/postdeploy/01_update_filesize_nginx.sh"

3. Now, zip your project again and deploy it to EB. Check the /var/log/ directory to monitor the hooks and script execution.

Conclusion

Congratulations! You just learned:

  1. How to deploy a simple Flask Web Application on AWS Elastic Beanstalk.
  2. How to use ebextensions scripts to automate SSL Generation and installation using Certbot.
  3. How to essentially update any config file on the underlying EC2 instance by using ebextension config files.

I hope you enjoyed learning about Elastic Beanstalk, it was a fun learning experience for me as well.

References

Escandell, M. (2021, April 18). How to get a SSL certificate running in AWS Elastic Beanstalk using Certbot. Medium. Retrieved August 3, 2022, from https://medium.com/edataconsulting/how-to-get-a-ssl-certificate-running-in-aws-elastic-beanstalk-using-certbot-6daa9baa3997

GOT A PROJECT?