DEV Community

Oluwademilade Oyekanmi for AWS Community Builders

Posted on โ€ข Edited on

1

๐Ÿš€ Deploying a Flask API on AWS EC2 with Nginx & Gunicorn: My Journey from Zero to Production

๐Ÿš€ The Beginning: A Daunting Challenge

If you had told me a few months ago that Iโ€™d be deploying a Flask API on an AWS EC2 instance, setting up a reverse proxy with Nginx, and configuring Gunicorn like a pro, I would have laughed and probably asked, "Me? Deploying a full-fledged API? Abeg, be serious." ๐Ÿ˜…

But here we are. I did it. And Iโ€™m still in awe.

I recently started learning Python, and honestly, taking on this project felt like staring at a mountain with no climbing gear. It was intimidating. The thought of wiring everything togetherโ€”Flask, EC2, Systemd, Gunicorn, Nginxโ€”felt like an impossible task. But if there's anything I've learned, it's that when something looks impossible, you just have to dive in, make mistakes, consult AI (a lot! ๐Ÿ˜‚), and smash bugs until it works.

This is the story of how I locked in, barely remembered to eat, and refused to sleep until I got my FunNumberAPI up and running!

๐Ÿ”— Full source code available on GitHub: FunNumberAPI


๐ŸŽฏ The Mission: Build & Deploy a Number Classification API

The goal was simpleโ€”at least, in theory.

I wanted to build an API that could take a number and tell you fun stuff about it:

โœ… Is it Prime?

โœ… Is it Perfect?

โœ… Is it an Armstrong number? (Yes, I had to Google what that was. ๐Ÿ˜…)

โœ… Is it Odd or Even?

โœ… What's its digit sum?

โœ… Can we fetch a random fun fact about it?

Sounds fun, right? Well, it wasโ€”until I had to deploy it. Thatโ€™s where the real battle began.


๐Ÿ”ฅ The Struggle: A Battle with Errors

Everything that could go wrong, went wrong.

First, Flask was fine on my local machine, but when I tried to deploy itโ€ฆ boom. Errors left, right, and centre.

Then Gunicorn started misbehaving.

Then systemd refused to start my service.

Then NGINX acted like it had never met me before.

At some point, I asked myself, "Why am I doing this again?" But the stubborn part of me refused to give up. So I dug deep, Googled endlessly, consulted AI (shoutout to my robotic mentor, ChatGPT ๐Ÿ˜†), and slowly started making progress.


๐Ÿ”ง The Breakthrough: Step-by-Step Deployment

After hours of debugging, frustration, and moments of victory, I finally got my Flask app LIVE on an AWS EC2 instance! ๐ŸŽ‰

Hereโ€™s how I did it:

๐Ÿ›  Step 1: Building the API

I built the backend using Flask, ensuring that it could classify numbers correctly and fetch fun facts. The full implementation, including all helper functions, can be found in my GitHub repository:

๐Ÿ”— API Implementation: FunNumberAPI/app.py

At this point, the API worked locally. But making it accessible to the world? Thatโ€™s where the real battle began.

โ˜ Step 2: Deploying to AWS EC2

I launched an Ubuntu EC2 instance, opened inbound rules for 22 (SSH), 80 (HTTP), and 5000 (Custom TCP) and connected to the instance via SSH

Next, I set up the environment:

sudo apt update && sudo apt upgrade -y # Update system
sudo apt install python3-pip nginx -y # Install Python & Pip
python3 -m venv .venv # Create a virtual environment
source .venv/bin/activate # Activate the virtual environment
pip install flask gunicorn flask_cors requests # Install required libraries
Enter fullscreen mode Exit fullscreen mode

Next, I cloned my repo

git clone https://github.com/MsOluwademilade/FunNumberAPI.git
cd FunNumberAPI
python3 app.py 
Enter fullscreen mode Exit fullscreen mode

Then I ran the app

gunicorn --bind 0.0.0.0:5000 app:app
Enter fullscreen mode Exit fullscreen mode

Tested it: http://<public-ip-of-ec2>:5000/api/classify-number?number=371 โœ…

โš™ Step 3: Setting Up systemd for Service Management

To keep the API running in the background and restart it on failures, I created a systemd service:

sudo nano /etc/systemd/system/flask-app.service
Enter fullscreen mode Exit fullscreen mode

And added:

[Unit] Description=Gunicorn instance to serve Flask app After=network.target

[Service] 
User=ubuntu 
WorkingDirectory=/home/ubuntu/FunNumberAPI ExecStart=/home/ubuntu/.venv/bin/gunicorn --workers 3 --bind 127.0.0.1:5000 app:app 
Restart=always

[Install] 
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode

Then, enabled and started the service:

sudo systemctl daemon-reload
sudo systemctl start flask-app
sudo systemctl enable flask-app
Enter fullscreen mode Exit fullscreen mode

Now, even if the server rebooted, my API would start automatically.

๐ŸŒ Step 4: Configuring NGINX as a Reverse Proxy

To expose my API on port 80 and avoid manually specifying port 5000, I configured NGINX:

sudo nano /etc/nginx/sites-available/default
Enter fullscreen mode Exit fullscreen mode

Replaced the contents with:

server {
    listen 80;
    server_name <public-ip-of-ec2>;

    location / {
        proxy_pass http://127.0.0.1:5000;
        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;
    }
}
Enter fullscreen mode Exit fullscreen mode

Restarted NGINX

sudo nginx -t
sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

And finally, my API was live on:

http://<public-ip-of-ec2>/api/classify-number?number=371
Enter fullscreen mode Exit fullscreen mode

๐Ÿ† Acknowledgements

  • Huge thanks to the HNG12 DevOps mentors for introducing this daunting yet rewarding challengeโ€”it pushed me beyond my limits and taught me so much.
  • Flask for making Python APIs a breeze ๐Ÿƒ
  • Numbers API for the fun facts ๐Ÿ”ข
  • You, for checking out this project! ๐ŸŽ‰

๐Ÿ—จ๏ธ Final Thoughts

Deploying this API wasnโ€™t just a technical challengeโ€”it was a mental endurance test. There were moments when I felt stuck, times when I considered rewriting the entire thing, but pushing through taught me invaluable lessons about Flask, deployment, debugging, and perseverance.

๐Ÿš€ If youโ€™re new to backend development and cloud deployment, take on projects that scare you. Youโ€™ll learn more than you ever thought possible.

If you found this helpful, letโ€™s connect! Drop a comment, share your own deployment struggles, or hit me up on GitHub. Letโ€™s keep building! ๐Ÿ”ฅ

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

Top comments (0)

Best Practices for Running  Container WordPress on AWS (ECS, EFS, RDS, ELB) using CDK cover image

Best Practices for Running Container WordPress on AWS (ECS, EFS, RDS, ELB) using CDK

This post discusses the process of migrating a growing WordPress eShop business to AWS using AWS CDK for an easily scalable, high availability architecture. The detailed structure encompasses several pillars: Compute, Storage, Database, Cache, CDN, DNS, Security, and Backup.

Read full post