DEV Community

Cover image for How to deploy a FastAPI app to AWS EC2 server.
Nick Langat
Nick Langat

Posted on

How to deploy a FastAPI app to AWS EC2 server.

Hello fellow tech enthusiasts Nick here. It's been a while since I posted an article but hey here I am and with a fresh one.
So a time comes when you have built an Python application using FastAPI and after testing it locally and pleased with its functionality, you wanna take it to the web and make it publicly accessible.
LOCAL SETUP
In this article we will bootstrap a simple application then commit it to Github and finally deploy it to an AWS EC2 instance.
We start by creating a local workspace on our machine so navigate to desktop and create a folder hello_fastapi and open it using your code editor.
Next let's create a virtual environment to hold our dependencies.

virtualenv env
Enter fullscreen mode Exit fullscreen mode

Then activate it using

env/Scripts/activate on windows
source env/bin/activate on linux/unix
Enter fullscreen mode Exit fullscreen mode

Now that we have our environment set up let's install what we need.

pip install fastapi uvicorn gunicorn psycopg2-binary
Enter fullscreen mode Exit fullscreen mode

You may add the deps depending on what your project will need in order to work.
With the deps installed we then create a file that will hold them all.

pip freeze > requirements.txt
Enter fullscreen mode Exit fullscreen mode

Next create a file called main.py at the root of the project and add the following code to it.

import uvicorn

if __name__ == "__main__":
    uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
Enter fullscreen mode Exit fullscreen mode

Then create another file at the root called app.py with the following code:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = ["*"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/", tags=["Root"])
async def read_root():
    return {"message": "Welcome to the API!"}
Enter fullscreen mode Exit fullscreen mode

Let's test the app to see if it is running well on our local browser:
Run the server by:

uvicorn  app:app --reload
Enter fullscreen mode Exit fullscreen mode

Next visit your browser at localhost and you should get greeted by

{"message":"Welcome to bills API!"}
Enter fullscreen mode Exit fullscreen mode

If everything works then we have a working app and we can procced to the next section.

VERSION CONTROL
While still in the root of the project we can issue the follwoing commands to push our code to Github:

git init
git add .
git commit -m 'initial'
git remote add origin <REMOTE URL HERE>
git push -u origin master
Enter fullscreen mode Exit fullscreen mode

If all goes well then you should have your code uploaded and stored on a Github repo. We are safe to proceed to the next step.
DEPLOYING TO AWS EC2
The assumption am making here is that you have an AWS account and have created a free tier EC2 server running on Ubuntu. Feel free to checkout docs on how to do that here.
These steps will work on any Ubuntu machine though so if you are on DigitalOcean, Linode or Oracle it should work well.
Let's ssh into our remote machine then:

ssh -i 'example.pem' ubuntu@ec2-IP-ADDRESS.us-east-2.compute.amazonaws.com
Enter fullscreen mode Exit fullscreen mode

Once you are inside the remote machine we need to install Python and NGINX.
Issue the following commands on the terminal:

sudo apt update
sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx curl
sudo -H pip3 install --upgrade pip
Enter fullscreen mode Exit fullscreen mode

Next create a folder that will carry our files:

mkdir apiv1 && cd apiv1

Then create and activate a virtual environment like we did before.
After that initiate git inside the folder and pull your code from github.

git init
git remote add origin <REPO URL>
git pull origin master
Enter fullscreen mode Exit fullscreen mode

Now we install our deps like so:

pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

Deactivate the virtualenv after running the local server and ensuring no errors are reported.
Next up we need to bind our application to a gunicorn module that serves as an interface to your application, translating client requests from HTTP to Python calls that your application can process.
So we start by creating a socket file:

sudo nano /etc/systemd/system/gunicorn.socket
Enter fullscreen mode Exit fullscreen mode

Add the following code to it:

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target
Enter fullscreen mode Exit fullscreen mode

Save and close that file. Next we create a service file:

sudo nano /etc/systemd/system/gunicorn.service
Enter fullscreen mode Exit fullscreen mode

Add the following code to it:

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/apiv1
ExecStart=/home/ubuntu/apiv1/env/bin/gunicorn \
          --access-logfile - \
          --workers 5 \
          --bind unix:/run/gunicorn.sock \
          --worker-class uvicorn.workers.UvicornWorker \
          app:app

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

Save and close as well.
Next start the Gunicorn socket:

sudo systemctl start gunicorn.socket
Enter fullscreen mode Exit fullscreen mode

Then enable it by:

sudo systemctl enable gunicorn.socket
Enter fullscreen mode Exit fullscreen mode

Now that Gunicorn is set up, next we’ll configure Nginx to pass traffic to the process.
Start by creating and opening a new server block in Nginx’s sites-available directory:

sudo nano /etc/nginx/sites-enabled/api
Enter fullscreen mode Exit fullscreen mode

Add the following lines to it:

server {
    listen 80;
    server_name server_domain_or_IP;
    location / {
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}
Enter fullscreen mode Exit fullscreen mode

Save this file as well. Test that the config is okay by:

sudo nginx -t
Enter fullscreen mode Exit fullscreen mode

If all is well then we need to restart the services so go aheda and:

sudo systemctl daemon-reload
sudo systemctl restart gunicorn
sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

One last step is to ensure that you have allowed HTTP access via port 80 on your instance's security group section. Do the same for port 443 if your app is served over HTTPS.
If all the above is done then go to your instance's public IP address or domain and hopefully you will see your app being displayed there.
WRAP UP
And that's it folks, if you made it here then a huge shoutout to you!
Today we built a simple Python app using FastAPI and deployed it to an EC2 Ubuntu server provided by AWS.
If you found this helpful the show some love by liking, commenting or sharing. You can also follow me on Twitter or visit my webite.
Thank you and till next time!

Discussion (0)