3

I have a FastAPI web application using Jinja2 templates, which is working fine on localhost, but not in production. The problem is that is not generating URLs for JavaScript and other static files correctly. I have deployed it on EC2 instance using gunicorn and nginx.

I have this line of code in my HTML file:

<script src="{{ url_for('static', path='js/login_signup.js') }}"></script>

The problem is that it is generating the URL like this:

<script src="http://127.0.0.1:8000/static/js/login_signup.js"></script>

What I want is to generate something like this:

<script src="http://my_domain.com/static/js/login_signup.js"></script>
1
  • Probably because you're not serving on 0.0.0.0, but you've given us no info. How are you starting your server? Commented Nov 23, 2022 at 15:14

2 Answers 2

2

Since you mentioned that you are using gunicorn, you would need to make sure you are binding gunicorn to 0.0.0.0 (see this answer for more details). For example:

gunicorn --bind 0.0.0.0:80 

Additionally, since you are using Nginx, make sure to configure your "server" config section, as described here (see this answer for more details on --proxy-headers flag as well):

 server {
        server_name example.com
        location / {
            proxy_redirect     off;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto $scheme;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-Host $server_name;

           ...
        }


    listen 443 ssl; 

If the above does not solve the issue for you, see other options below.

Option 1

You can use realtive paths instead, as described here and here. Example:

<link href="static/styles.css'" rel="stylesheet">

Option 2

You can create a custom function (i.e., my_url_for() in the exmaple below), which will be used to replace the URL's domain name (hostname)—you can omit the port number when replacing the hostname, if you are relying on the default port of HTTP (80) or HTTPS (443) protocol—and use that function inside your Jinja2 templates instead of the usual url_for() function. If you would also like to include query parameters in the URL, rather than just path parameters, have a look at this answer and this answer. Example:

Backend

from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from typing import Any
import urllib

app = FastAPI()

def my_url_for(request: Request, name: str, **path_params: Any) -> str:
    url = request.url_for(name, **path_params)
    parsed = list(urllib.parse.urlparse(url))
    #parsed[0] = 'https'  # Change the scheme to 'https' (Optional)
    parsed[1] = 'my_domain.com'  # Change the domain name
    return urllib.parse.urlunparse(parsed)
    

app.mount('/static', StaticFiles(directory='static'), name='static')
templates = Jinja2Templates(directory='templates')
templates.env.globals['my_url_for'] = my_url_for

Frontend

<link href="{{ my_url_for(request, 'static', path='/styles.css') }}" rel="stylesheet">
Sign up to request clarification or add additional context in comments.

Comments

0

Serve on 0.0.0.0 instead of 127.0.0.1. If you're using uvicorn which is the default web server for FastAPI, you need to pass --host 0.0.0.0 when starting the server. For other servers, look up the equivalent flag.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.