Home > OS >  FastAPI with nginx does not serve static files in HTTPS
FastAPI with nginx does not serve static files in HTTPS

Time:10-16

I have a small, test FastAPI web application that is serving a simple HTML page that requires a css style sheet located in the static folder. It is installed on a Linode server (Ubuntu 20.04 LTS), nginx, gunicorn, uvicorn workers, and supervisorctl. I have added a certificate using certbot.

The application works fine in http but does not access the static files in https. When accessed in http all static-based features work but when accessed with https it lacks all styling from css stylesheet. I need to get this working so I can load a much more complex app that needs css and other static folder-stored features.

The file structure is:

/home/<user_name>/application
- main.py
- static
   |_ css
   |_ bootstrap
- templates
   |_ index.html

main.py:

import fastapi
import uvicorn
from fastapi import Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates


api = fastapi.FastAPI()

api.mount('/static', StaticFiles(directory='static'), name='static')
templates = Jinja2Templates(directory="templates")


@api.get('/')
@api.get('/index', response_class=HTMLResponse)
def index(request: Request):
    message = None
    return templates.TemplateResponse("index.html", {"request": request,
        'message': message})


if __name__ == '__main__':
    uvicorn.run(api, port=8000, host='127.0.0.1')

nginx is at /etc/nginx/sites-enabled/<my_url>.nginx

server {
    listen 80;
    server_name www.<my_url>.com <my_url>.com;
    server_tokens off;
    charset utf-8;

    location / {
        try_files $uri @yourapplication;
    }

    location /static {
        gzip            on;
        gzip_buffers    8 256k;

        alias /home/<user_name>/application/static;
        expires 365d;
    }


    location @yourapplication {
        gzip            on;
        gzip_buffers    8 256k;

        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Protocol $scheme;
    }
  }

server {
    listen              443 ssl;
    server_name         www.<my_url>.com;
    ssl_certificate /etc/letsencrypt/live/<my_url>.com/fullchain.pem; # mana>
    ssl_certificate_key /etc/letsencrypt/live/<my_url>.com/privkey.pem; # ma>
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    location / {
        try_files $uri @yourapplication;
    }

  location /static {
        gzip            on;
        gzip_buffers    8 256k;

        alias /home/<user_name>/application/static;
        expires 365d;
    }

    location @yourapplication {
        gzip            on;
        gzip_buffers    8 256k;

        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Protocol $scheme;
    }
}

and am serving using supervisor script:

[program:api]
directory=/home/<user_name>/application
command=gunicorn -b 127.0.0.1:8000 -w 4 -k uvicorn.workers.UvicornWorker main:api
environmentenvironment=PYTHONPATH=1
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
stderr_logfile=/var/log/app/app.err.log
stdout_logfile=/var/log/app/app.out.log

The css stylesheet is called in the html using url_for like this:

<link href="{{ url_for('static', path='/css/ATB_style.css') }}" rel="stylesheet">

I have tried a whole host of modifications to the location /static block in nginx including:

  • adding slash after static in either line or both
  • trying to add https://static or https://www.<my_url>.com/home/<my_url>/application/static
  • adding and removing the location static from the http and https lines
  • changing proxy_pass to https://127.0.0.1:8000;
  • added root /home/<user_name>/application to the server section

I have loaded this server twice, once letting certbot modify the nginx file the second, and current configuration, where I did it manually. I am at a complete loss on what to do.

CodePudding user response:

Thanks to @AdramKhan for the comment that solved this problem. Turns out I needed to add a meta line to my html page to allow access to the css stylesheet with https:

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

CodePudding user response:

I'd think you want the server to handle it. If you just setup a separate block on port 80 to convert all requests to 443 (HTTPS) permanently, you'd be good:

server {
    listen 80;
    server_name yourserver.com;
    return 301 https://yourserver.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name yourserver.com;
    ...
}```
  • Related