Introduction
As a data scientist eager to deploy a new project through the web, you might think that once you have a trained model or an API that things are going to be straightforward after that, which could be the case with a managed or a more expensive solution. However, if you prefer a hands-on approach, things can be a bit challenging.
One common issue you might encounter is when attempting to connect your brand new website to your FastAPI app, is receiving a message stating that the connection is not secure. This problem arises because most tutorials demonstrate how to deploy FastAPI through HTTP, but you need HTTPS to ensure a secure connection.
This is where this guide comes in, to document how you can fix that issue easily. Most of this content is based on the tutorial given by the creator of FastAPI himself here
The main stack I used for this is:
1.AWS free tier EC2 instance
2.Elastic IP address that allows your API to have a static IP (this is included in the free tier without additional cost)
3.FastAPI app + Docker
4.Namecheap for the domain and DNS settings (you can get a domain for $2 a month)
AWS setup
The first step is to Launch AWS EC2 Instance, and you can do so by doing the following:
Sign in to your AWS account and go to the EC2 dashboard.
Choose an instance type (t2.micro is available for free tier) and follow the steps to configure the instance.
During the configuration, make sure to assign an Elastic IP to your instance to get a static public IP, which will be used in the next step.
Namecheap setup
Log in to your Namecheap account and navigate to the “Domain List.”
Find your domain and click on “Manage” next to it.
Go to the “Advanced DNS” tab and add an “A Record” pointing to your EC2 instance’s Elastic IP with a subdomain, which I chose to be fastapi-traefik I also added *.fastapi-traefik subdomain to point to the same IP address.
FastAPI
The code for the app does is not affected by switching from HTTP to HTTPS.
here is a sample
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_main():
print("here")
return {"message": "Hello world of FastAPI with Traefik"
Docker
This is where the main difference is when deploying over HTTP vs HTTPS by defining 2 docker-compose files and running them separetely.
The following is the content of the Dockerfile
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.8
COPY ./app /app/
At this point we need to define two different docker-compose files, one for the app service and one for a traefik service which will handle the HTTPS configuration
The main docker-compose.yml , note that in the example you have to provide your own domain. For now I have used the subdomain fastapi-traefik
services:
backend:
build: ./
restart: always
labels:
- traefik.enable=true
# Services in traefik is just something that can receive requests
- traefik.http.services.app.loadbalancer.server.port=80
- traefik.http.routers.app-http.entrypoints=http
- traefik.http.routers.app-http.rule=Host(`fastapi-traefik.abc.xyz`)
- traefik.docker.network=traefik-public
- traefik.http.routers.app-https.entrypoints=https
- traefik.http.routers.app-https.rule=Host(`fastapi-traefik.abc.xyz`)
- traefik.http.routers.app-https.tls=true
- traefik.http.routers.app-https.tls.certresolver=le
- traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
- traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
- traefik.http.routers.app-http.middlewares=https-redirect
networks:
- traefik-public
networks:
traefik-public:
external: true
- And the traefik docker compose file docker-compose.traefik.yml
“ …Traefik is an open-source reverse proxy and load-balancer for HTTP and TCP-based applications that is easy, dynamic, automatic, fast, full-featured, production-proven, provides metrics, and integrates with every major cluster technology…”
Note that you need to add the correct email address here.
services:
traefik:
image: traefik:v2.3
ports:
# Map port 80 in the remote server with port 80 in the conatiner running traefik
- 80:80
- 443:443
restart: always
volumes:
# So traefik can communicate with Docker
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik-public-certificates:/certificates
command:
- --providers.docker
- --providers.docker.exposedbydefault=false
- --entrypoints.http.address=:80
- --entrypoints.https.address=:443
- --certificatesresolvers.le.acme.email=abc@gmail.com
- --certificatesresolvers.le.acme.storage=/certificates/acme.json
- --certificatesresolvers.le.acme.tlschallenge=true
- --accesslog
- --log
networks:
- traefik-public
volumes:
traefik-public-certificates:
networks:
traefik-public:
external: true
It is also handy to add .dockerignore file to avoid bloating the container once deployed
Deploying the App
You can create a Github repo and push the code to it, then clone SSH into the EC2 instance and clone it. Or if you are looking for a quick test you can copy the code directly using rsync
rsync -avz -e "ssh -i ~/key.pem" . ubuntu@fastapi-traefik.abc.xyz:/home/ubuntu/
Which will copy all the content of the current directory to the AWS instance.
- Create the network which will be used by the services
docker network create traefik-public
docker-compose -f docker-compose.traefik.yml up
docke-compose -f docker-compose.yml up
Once this is complete you can now access the app through HTTPS!!