15

I'm trying to run a fastapi app with SSL.

I am running the app with uvicorn.

I can run the server on port 80 with HTTP,

if __name__ == '__main__':
    uvicorn.run("main:app", port=80, host='0.0.0.0', reload = True, reload_dirs = ["html_files"])

To run the port with HTTPS, I do the following,

if __name__ == '__main__':
    uvicorn.run("main:app", port=443, host='0.0.0.0', reload = True, reload_dirs = ["html_files"], ssl_keyfile="/etc/letsencrypt/live/my_domain/privkey.pem", ssl_certfile="/etc/letsencrypt/live/my_domain/fullchain.pem")

How can I run both or simply integrate https redirect?

N.B: This is a setup on a server where I don't want to use nginx, I know how to use nginx to implement https redirect.

Zabir Al Nazi
  • 10,298
  • 4
  • 33
  • 60

3 Answers3

9

Run a subprocess to return a redirect response from one port to another.

main.py:

if __name__ == '__main__':
    Popen(['python', '-m', 'https_redirect'])  # Add this
    uvicorn.run(
        'main:app', port=443, host='0.0.0.0',
        reload=True, reload_dirs=['html_files'],
        ssl_keyfile='/path/to/certificate-key.pem',
        ssl_certfile='/path/to/certificate.pem')

https_redirect.py:

import uvicorn
from fastapi import FastAPI
from starlette.requests import Request
from starlette.responses import RedirectResponse

app = FastAPI()


@app.route('/{_:path}')
async def https_redirect(request: Request):
    return RedirectResponse(request.url.replace(scheme='https'))

if __name__ == '__main__':
    uvicorn.run('https_redirect:app', port=80, host='0.0.0.0')
Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
aaron
  • 39,695
  • 6
  • 46
  • 102
8

Use HTTPSRedirectMiddleware. This will enforce redirection to https on any incoming requests.

from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware
app.add_middleware(HTTPSRedirectMiddleware)
Chris
  • 18,724
  • 6
  • 46
  • 80
  • My ssl certificate is not in local machine, it's on heroku. But tried this to add and test in my local machine, which creates an error. Any suggestion would be appreciated. – Mahmudur Rahman Shovon Apr 25 '22 at 18:31
  • 3
    Even with `HTTPSRedirectMiddleware` installed, I'm getting `The connection was reset` in Firefox and `curl: (52) Empty reply from server` with curl for HTTP requests. This is same behaviour as without the middleware. It makes sense to me, because Uvicorn says it is only listening for HTTPS on the port. How's it supposed to work? – kthy Jul 28 '22 at 15:37
  • Not working for me :/ – ArnoV Jan 01 '23 at 08:44
  • @ArnoV I am afraid that _"Not working..."_ is very abstract and vague, without stating what the case is, as well as any debugging details. I would also suggest you have a look at related answers [**here**](https://stackoverflow.com/a/71306247/17865804) and [**here**](https://stackoverflow.com/a/74550974/17865804), which might help with the issue you are facing. – Chris Jan 01 '23 at 08:50
  • What I mean by "not working" is that when my user types "example.com" in the search bar they get a negative answer and they have to explicitly type "HTTPS://example.com" – ArnoV Jan 01 '23 at 09:23
0

I think you can redirect all traffic from port 80 to port 443 on the OS level using. For example, on Ubuntu, by run in the terminal:

sudo iptables -t nat -L
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 443 # 80 -> 443