Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kubopanda/4dcee98c620fb4d031601cc0e35ce335 to your computer and use it in GitHub Desktop.
Save kubopanda/4dcee98c620fb4d031601cc0e35ce335 to your computer and use it in GitHub Desktop.
Q & A from Traefik Online Meetup: Deploying FastAPI apps with HTTPS powered by Traefik

Q & A from Traefik Online Meetup: Deploying FastAPI apps with HTTPS powered by Traefik

Question: Will you use Docker in the dev environment?

Answer: Not this time, just to save time (there's a lot to cover), although I'm sharing a couple of development tricks in the end.

Question: Why is the convention ‘app’ not 'api'?

Answer: To simplify things. It might be more familiar for people coming from other frameworks. Also because you can serve things like templates rendered on the backend, so, to avoid confusion. But you can also name the object differently if that works better for you.

Question: How do you get the python icon in your terminal, by some Powerlevel10k extension?

Answer: I use Zsh with a bunch of extensions. And I also use https://starship.rs/

Question: I'm interested in configuring Okta to work with FastAPI and OIDC. I want my app to send users to Okta for login and get the current user. I know how to do it with Flask, but I couldn't find the right OIDC package for FastAPI.

Answer: FastAPI is based on OpenAPI, and OpenAPI has integrated support for OIDC (and other forms of OAuth2). So, you don't really need any plugin. It's all integrated in FastAPI. Nevertheless, it's not properly documented yet. That's one of my priorities for FastAPI in the coming months. But as a quick hint, this is what you need to use in FastAPI: https://github.com/tiangolo/fastapi/blob/master/fastapi/security/open_id_connect_url.py#L10

Question: Any recommendations on good design patterns to allow either bearer token OR x-api-key in headers for authorization?

Answer: Yes! That's another thing I need to document in the coming months, once I can put more time to FastAPI. In short, all the security base utilities (classes) have a setting auto_error=True. You can create them with auto_error=False, then require both in a single dependency, and then in that dependency check if none was valid and raise the HTTPException.

And there's a tip for that that is frequently missed: you almost never need to subclass the FastAPI security utilities. You can just require them as dependencies in another dependency, and put your additional logic (raising HTTPExceptions) from that dependency. So, all you have to do is write a simple function (not sub-classes).

Question: Are you going to use a database?

Answer: Not this time, only the bare minimum to focus on deploying with Traefik and HTTPS, there's a lot to cover as we are deploying from scratch, otherwise it could take hours :)

Question: Is FastAPI installed in Docker?

Answer: tThe Dockerfile uses the official base image that already includes FastAPI, so it's not necessary for this quick example. But in your case, and for production, it's recommended to install and pin the version ranges that you know work well for your app.

That also depends on the tools you are using, e.g. Poetry, pip, etc.

Check more about that in the docs for that in the official Docker image: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker#dependencies-and-packages

Question: Is it safe to forward user info within the header?

Answer: Worst answer ever: it depends :)

But this is one of the cases where HTTPS is vital. You should probably not send any private user info without HTTPS. But if you are using HTTPS (e.g. provided by Traefik as here), the fact of sending user data in headers would not be a problem per se.

Nevertheless, you would probably send that data in the body of requests or responses.

Question: Would you use middleware to add something like Sentry?

Answer: Yep, absolutely. I currently do :) In fact, you can use a dependency to add the current user to the Sentry context. But that deserves a blog post/article on its own.

Question: Is there any package available to generate FastAPI production boilerplate similar to Django-cookiecutter.

Answer: Yes. This set of configs is based on the official project generator: https://github.com/tiangolo/full-stack-fastapi-postgresql

Question: What is the best way to contribute to FastAPI?

Answer: Thanks for asking that!

There are many ways, some are super simple: https://fastapi.tiangolo.com/help-fastapi/

For example, one of the best ways, is actually to help others with their questions. Those who do that are the FastAPI Experts: https://fastapi.tiangolo.com/fastapi-people/#most-active-users-last-month

Question: Would it be possible to have a tutorial for a simple text search engine?

Answer: Unfortunately, search is actually much more complex than what it seems (similar to HTTPS). But you could check Jina, a search engine powered by FastAPI and deep learning. Or also the official ElasticSearch docs: https://elasticsearch-py.readthedocs.io/en/7.9.1/async.html#asgi-applications-and-elastic-apm

Question: Would you please explain the part about randomness a bit more? And. what did you say about the random stuff with Docker? Why is entropy needed?

Answer: It's actually because docker-compose tries to read "random" data generated by the machine. Even for operations that don't need that. And the machine that was just created doesn't have enough of that generated "random" data to give it.

It's actually not related to this deployment at all, but an issue with Docker Compose: docker/compose#6678

Question: uvicorn runs by default on 5000, but the docker compose ports 80:80. Did we update uvicorn.run to run on 80?

Answer: Nope, the official Docker image does that internally. It also auto-tunes the number of workers to be created by Gunicorn based on the server where it is deployed, etc.

Question: I didn't get why you were using uvicorn when calling FastAPI by command line and not using uvicorn whn using docker.

Answer: Because the official Docker image does all that for you.

Question: Why uvicorn is needed? Also, just uvicorn is enough for a production app? Or do I need to use gunicorn as well?

Answer: Uvicorn is the server, FastAPI is only the framework. Gunicorn can start multiple Uvicorns at the same time. Uvicorn would mainly run a single process.

Question: What is the docker-compose.override.yml doing?

Answer: Not much in this example, it is useful for development only, to map the ports locally, etc.

Question: For the HTTPS certificate, will traefik re-issue the certificate over and over if we keep restarting the Traefik container? if that happens we hit the Let’s Encrypt domain limit? How can we avoid this behaviour?

Answer: When you mount the volume for the certificates, they are preserved across restarts, so Traefik will not re-acquire certificates that are not needed. It will renew the certificates automatically when they are about to expire. But if you mount the volume there would be no problem.

Question: Is it insecure to mount the Docker socket to the container?

Answer: You are mounting it only in the Traefik container, not in any other, and in read-only mode, so only Traefik will be able to read data there (the labels). And Traefik is open source, so you can actually review its internal code if you needed to.

Question: Is there a way to manually tell Traefik to reload certs?

Answer: I'm actually not sure, I haven't tried that, as I'm normally trying to avoid renewing too frequently (e.g. redeploying the entire cloud server again). As Let's Encrypt has a rate limit. But if you remove the current certificates (e.g. remove the volume) then Traefik will re-acquire them.

Question: Will there be a fast-traefik, hoping for a single cli to do this all settings:)

Answer: You can probably use the FastAPI project generator that uses Traefik everywhere: https://github.com/tiangolo/full-stack-fastapi-postgresql

But there's actually no need for any other type of deeper integration between FastAPI and Traefik, they just work. :)

Question: You’ve created the https-redirect middleware on both the Traefik and FastAPI container. Do we need both? Does Traefik detect conflicts?

Answer: Clever! Good catch! One will override the other, unless you set different names. But as both are configured the same way, it won't matter.

What I would do is set it only in the main Traefik, and then reuse it in any other stacks. But for the tutorial it was easier to understand if all the needed things were together.

Question: As this is a tutorial, what other things should we consider before deploying this to production?

Answer: That's probably an infinite topic, but some of the things to check:

Handling FastAPI versions: https://fastapi.tiangolo.com/deployment/versions/ The project generator with a reusable structure: https://github.com/tiangolo/full-stack-fastapi-postgresql The docs for the official Docker image: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker#how-to-use

But apart from extra details in those, what you saw already has good practices in terms of deployment (Docker with restarts), servers, security with HTTPS, etc. So this should be quite enough at least to start. Then you will optimize that forever, because that's what we developers do :p ...but this should be a very good starting point.

Question: if I have generated a TSL certificate using certbot before migrating to Traefik, will Traefik take in charge that certificate?

Answer: Traefik will probably re-acquire the certificate. But that's normally not a problem, unless you already hit the Let's Encrypt rate limit by reaquiring the same certificate many times that the same week.

Question: So, to call the API now because of the auth, we have to send something special in the header?

Answer: I understand you refer to the HTTP Basic Auth handled by Traefik, right?

Basic Auth is very useful mostly for applications that you don't necessarily control, like a visualization. For your API with FastAPI, you will probably be better off by adding authentication internally with the FastAPI security utilities, and then use Traefik mainly for handling the traffic and HTTPS.

But if for some reason you need to communicate with something using HTTP Basic Auth, the browser normally takes care of it for you, it asks for the username and password, and then it remembers it for the next time. But if you need to communicate with something using Basic Auth from code, yes, that works sending the authentication in headers. Check an example with HTTPX: https://www.python-httpx.org/quickstart/#authentication

Question: Is the GitHub repo made available for public?

Answer: The FastAPI GitHub repo is here: https://github.com/tiangolo/fastapi The Traefik GitHub repo is here: https://github.com/traefik/traefik The materials of the talk are not yet available, I will make them available later and announce it on Twitter. But meanwhile, you can check the project generator, in which this talk was based on: https://github.com/tiangolo/full-stack-fastapi-postgresql

Question: With basic auth for a small users, does it also work?

Answer: If you mean for multiple users, yes. You can specify multiple pairs of username and password.

Question: Are there any auth middlewares other than basic-auth for Traefik?

Answer: That's probably gonna be difficult to achieve. Traefik can add an HTTP Basic Auth middleware because it's part of the HTTP standards, and it's handled automatically between the browser and server. Any other method that is more sophisticated will probably require integration with the actual app itself, and the frontend of that app, e.g. for doing social authentication or similar.

Question: I'm pretty new to Docker but how does Traefik compare to Kubernetes or Swarm?

Answer: Imagine a presidential motorcade or convoy. Docker is the engine on each car. Kubernetes or Swarm are two types of, let's say, radio systems coordinating each of the cars. Traefik would be the armor, or part of it, that could protect one single car or many (with HTTPS). Traefik is also part of the security guys that know everyone, and let police bikes and cars join the convoy or not, and allow some people to enter into the cars (routing requests).

You could have a single car, without armor, without a radio system: only with Docker.

But you couldn't have a radio system without cars to control. So, when you deploy Docker with Swarm mode, it always comes with Docker inside.

And when you deploy or use Kubernetes, it's like calling a taxi company, they have the radio system (like the convoy), and you talk to the company, but they always have cars (taxi cabs), it's never the radio alone. New versions of Kubernetes don't use Docker, but an alternative engine (or parts of Docker's engine).

And of course, you can have a car, or even a convoy, without any armor, or without much control of who joins or not (without Traefik).

Maybe it's not the best analogy but I tried. 😅🤷

Question: With Traefik would it be also easy to integrate with Azure ad for user management?

Answer: Traefik and Azure don't overlap in functionality, so they wouldn't clash. If you refer to authentication with Azure for your app, then that would require integration with your app's code, there's nothing Traefik can do. It's not lack of support from Traefik, but that it would be technologically unfeasible. Check also the answer for question 29.

Question: Please explain scale the container to see how Traefik manages round robin.

Answer: I'm not sure I understand the question correctly. If you mean a distributed cluster of Traefik instances, with HTTPS support in all of them, synchronizing the HTTPS certificates, etc. That's a feature of Traefik Enterprise, you can check the docs here: https://traefik.io/traefik-enterprise/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment