Serving a dash app using waitress on an actual server running nginx gives me 404 errors

Question:

I’m trying to serve a dash app on an actual server – locally running works all fine – that is running nginx, has a ssl certificate and proxy passes the oncoming traffic to the port I specify in waitress.serve.

I can run a trial flask app but trying to serve a dash app does not return anything but Loading....

Here’s the setup:

/etc/nginx/sites-enabled/default:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    ## Redirects all traffic to the HTTPS host
    root /nowhere; ## root doesn't have to be a valid path since we are redirecting
    rewrite ^ https://$host$request_uri? permanent;
}
server{
    # SSL configuration
    #
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    ## Strong SSL Security
    ssl on;
    ssl_certificate /etc/letsencrypt/live/FQDN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/FQDN/privkey.pem;
    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
    ssl_verify_client off;
    ssl_protocols  TLSv1.2 TLSv1.3;
    ssl_session_cache  builtin:1000  shared:SSL:10m;
    ssl_prefer_server_ciphers   on;
    add_header Strict-Transport-Security max-age=31536000;
    add_header X-Content-Type-Options nosniff;
    
    root /var/www/html;

    # Add index.php to the list if you are using PHP
    index index.html index.htm index.nginx-debian.html;

    server_name FQDN;

    location / {

        proxy_pass http://IP:8050;
        proxy_set_header X-Real-IP $remote_addr;

        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
    }
}

In my home directory on the server – I’m not logged in as root – I have the code for the (test) apps.

Trying to serve the following test app works flawlessly:

from flask import Flask
from waitress import serve

app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1 style='color:blue'> A very simple flask server !</h1>"

if __name__ == "__main__":
    serve(app, host='0.0.0.0', port=8050, url_scheme='https')

However, trying to serve the following MWE test app fails:

from flask import Flask
from waitress import serve
from dash import Dash
import dash_core_components as dcc
import dash_html_components as html

server = Flask(__name__)
app = Dash(
    __name__,
    server=server,
    url_base_pathname='/'
)
                          
app.layout = html.Div(
    html.H1(
        "A very simple dash app on a flask server !",
        style={'color': 'blue'},
    ),

)

@server.route("/")
def my_dash_app():
    return app.index()

if __name__ == "__main__":
    serve(server, host='0.0.0.0', port=8050, url_scheme='https')

I’m using VSCode with the ssh plugin and so I have a natural ssh tunnel through which I actually can access the latter app on http://localhost:8050/.

Inspecting the source code of the failed serve at view-source:https://FQDN/, I find the following:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Dash</title>
        <link rel="icon" type="image/x-icon" href="/_favicon.ico?v=2.6.1">
        
    </head>
    <body>
        
<div id="react-entry-point">
    <div class="_dash-loading">
        Loading...
    </div>
</div>

        <footer>
            <script id="_dash-config" type="application/json">{"url_base_pathname":"/","requests_pathname_prefix":"/","ui":false,"props_check":false,"show_undo_redo":false,"suppress_callback_exceptions":false,"update_title":"Updating...","children_props":{"dash_core_components":{"Checklist":["options[].label"],"Clipboard":[],"ConfirmDialog":[],"ConfirmDialogProvider":[],"DatePickerRange":[],"DatePickerSingle":[],"Download":[],"Dropdown":["options[].label"],"Graph":[],"Input":[],"Interval":[],"Link":[],"Loading":[],"Location":[],"LogoutButton":[],"Markdown":[],"RadioItems":["options[].label"],"RangeSlider":[],"Slider":[],"Store":[],"Tab":[],"Tabs":[],"Textarea":[],"Tooltip":[],"Upload":[]},"dash_html_components":{"A":[],"Abbr":[],"Acronym":[],"Address":[],"Area":[],"Article":[],"Aside":[],"Audio":[],"B":[],"Base":[],"Basefont":[],"Bdi":[],"Bdo":[],"Big":[],"Blink":[],"Blockquote":[],"Br":[],"Button":[],"Canvas":[],"Caption":[],"Center":[],"Cite":[],"Code":[],"Col":[],"Colgroup":[],"Content":[],"Data":[],"Datalist":[],"Dd":[],"Del":[],"Details":[],"Dfn":[],"Dialog":[],"Div":[],"Dl":[],"Dt":[],"Em":[],"Embed":[],"Fieldset":[],"Figcaption":[],"Figure":[],"Font":[],"Footer":[],"Form":[],"Frame":[],"Frameset":[],"H1":[],"H2":[],"H3":[],"H4":[],"H5":[],"H6":[],"Header":[],"Hgroup":[],"Hr":[],"I":[],"Iframe":[],"Img":[],"Ins":[],"Kbd":[],"Keygen":[],"Label":[],"Legend":[],"Li":[],"Link":[],"Main":[],"MapEl":[],"Mark":[],"Marquee":[],"Meta":[],"Meter":[],"Nav":[],"Nobr":[],"Noscript":[],"ObjectEl":[],"Ol":[],"Optgroup":[],"Option":[],"Output":[],"P":[],"Param":[],"Picture":[],"Plaintext":[],"Pre":[],"Progress":[],"Q":[],"Rb":[],"Rp":[],"Rt":[],"Rtc":[],"Ruby":[],"S":[],"Samp":[],"Script":[],"Section":[],"Select":[],"Shadow":[],"Slot":[],"Small":[],"Source":[],"Spacer":[],"Span":[],"Strike":[],"Strong":[],"Sub":[],"Summary":[],"Sup":[],"Table":[],"Tbody":[],"Td":[],"Template":[],"Textarea":[],"Tfoot":[],"Th":[],"Thead":[],"Time":[],"Title":[],"Tr":[],"Track":[],"U":[],"Ul":[],"Var":[],"Video":[],"Wbr":[],"Xmp":[]},"dash_table":{"DataTable":[]}}}</script>
            <script src="/_dash-component-suites/dash/deps/[email protected]_6_1m1663249656.12.1.min.js"></script>
<script src="/_dash-component-suites/dash/deps/[email protected]_6_1m1663249656.14.0.min.js"></script>
<script src="/_dash-component-suites/dash/deps/[email protected]_6_1m1663249656.14.0.min.js"></script>
<script src="/_dash-component-suites/dash/deps/[email protected]_6_1m1663249656.8.1.min.js"></script>
<script src="/_dash-component-suites/dash/dash-renderer/build/dash_renderer.v2_6_1m1663249656.min.js"></script>
<script src="/_dash-component-suites/dash/dcc/dash_core_components.v2_6_1m1663249656.js"></script>
<script src="/_dash-component-suites/dash/dcc/dash_core_components-shared.v2_6_1m1663249656.js"></script>
<script src="/_dash-component-suites/dash/html/dash_html_components.v2_0_5m1663249656.min.js"></script>
<script src="/_dash-component-suites/dash/dash_table/bundle.v5_1_5m1663249656.js"></script>
            <script id="_dash-renderer" type="application/javascript">var renderer = new DashRenderer();</script>
        </footer>
    </body>
</html>

where already the favicon can not load – checking view-source:https://FQDN/_favicon.ico?v=2.6.1:

<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

i.e., something with the paths seems to go wrong but I’m not knowledgeable enough w.r.t. nginx/flask/dash and would welcome any hints.

Thanks a lot!

Asked By: gothicVI

||

Answers:

Finally found the answer. It seems that my nginx config was faulty. Here’s a working one:

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

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name example.com;

    ssl_certificate /path/to/ssl/certificate.crt;
    ssl_certificate_key /path/to/ssl/private.key;

    location / {
        proxy_pass http://localhost:8050;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Answered By: gothicVI