Deploying FastAPI App over HTTPS with Traefik: A Quick Step-by-Step Guide

Mo Abdelhady profile picture

Mo A. Abdelhady

August 3, 2023

A quick guide on deploying FastAPI applications over https

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
  1. 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.

  1. 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!!