Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mod_wsgi to serve a python dash script on Apache2 #585

Closed
dgwyther opened this issue Jun 22, 2020 · 6 comments
Closed

mod_wsgi to serve a python dash script on Apache2 #585

dgwyther opened this issue Jun 22, 2020 · 6 comments

Comments

@dgwyther
Copy link

dgwyther commented Jun 22, 2020

Hi Graham

I'm trying to host a plotly-dash on an Apache2 using mod_wsgi. I've posted about this issue at StackOverflow.

Essentially, with what looks like the normal *.wsgi configuration:

#!/usr/bin/python
import sys
sys.path.insert(0,"/home/ubuntu/dashboards/")
from dashGAF import server as application

I get a 404 not found page (subtly different from the standard Apache 404 not found page). This leads me to believe there is something in the mod_wsgi configuration that hasn't worked.

But if I edit the *.wsgi file to from dashGAF import app as application then I no longer get a 404, but I get a 500 Internal Server error. Apache log says: TypeError: 'Dash' object is not callable.

More info:

  • I had originally installed mod_wsgi with apt install (following this link), but following advice from your help to others, I uninstalled and reinstalled with pip install mod_wsgi (and with sudo ... as well) and configured the mods-available file with mod_wsgi-express module-config.

Happy to paste any output or logs as requested. (and for it to be here or StackOverflow).

Cheers
Dave

I would appreciate any and all help in setting this up to work.

@GrahamDumpleton
Copy link
Owner

You have various things wrong in your Apache configuration. SO says you have:

WSGIDaemonProcess dashGAF user=ubuntu group=ubuntu home=/home/ubuntu threads=5
WSGIScriptAlias /dashGAF /var/www/html/wsgi/dashGAF.wsgi
    <Directory /home/ubuntu/dashboards>
        WSGIProcessGroup dashGAF
            WSGIApplicationGroup %{GLOBAL}
            WSGIScriptReloading On
        Require all granted
    </Directory>

The path for the Directory directive is wrong and you don't need WSGIScriptReloading.

It is also a bad idea to add your WSGI script file under /var/www.html if that is what DocumentRoot is set to for the server as it means someone can download your source code.

For a start, you want to use:

WSGIDaemonProcess dashGAF user=ubuntu group=ubuntu home=/home/ubuntu threads=5
WSGIScriptAlias /dashGAF /var/www/html/wsgi/dashGAF.wsgi

WSGIProcessGroup dashGAF
WSGIApplicationGroup %{GLOBAL}

The rest is irrelevant.

If you move the WSGI script alias outside of DocumentRoot, you will need the Directory directive again for where you place it, but with just the Require all granted within it.

Try those changes for a start.

Also indicate what URL path you are using to access it.

If the WSGI application is correct setup, you shouldn't need:

routes_pathname_prefix='/dashGAF/'

in which case the URL path you would use would be:

/dashGAF/

Right now it will probably only work if you use:

/dashGAF/dashGAF/

because you incorrectly have set routes_pathname_prefix where as a Flask application should automatically know to do that due to SCRIPT_NAME variable passed through from the WSGI server. That is, Flask implements:

@dgwyther
Copy link
Author

Hi Graham,
Thank you for the very prompt and helpful reply.

I have edited both
/etc/apache2/sites-enabled/dash.conf:

WSGIDaemonProcess dashGAF user=ubuntu group=ubuntu home=/home/ubuntu threads=5
WSGIScriptAlias /dashGAF /var/www/html/wsgi/dashGAF.wsgi

WSGIProcessGroup dashGAF
WSGIApplicationGroup %{GLOBAL}

and
/etc/apache2/sites-available/dash.conf:

WSGIDaemonProcess dashGAF user=ubuntu group=ubuntu home=/home/ubuntu threads=5
WSGIScriptAlias /dashGAF /var/www/html/wsgi/dashGAF.wsgi

WSGIProcessGroup dashGAF
WSGIApplicationGroup %{GLOBAL}

(I'm not sure how I ended up with both sites-available and sites-enabled. This error on my part may be part of the issue?)

My script file:
/home/ubuntu/dashboards/dashGAF.py

# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
#external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__)
server = app.server
...

And my *.wsgi file:
/var/www/html/wsgi/dashGAF.wsgi

#!/usr/bin/python
import sys
sys.path.insert(0,"/home/ubuntu/dashboards/")
from dashGAF import server as application

I am accessing this in a browser via my VM IP, i.e. I was trying 144.etc.etc.etc/dashGAF. As you also suggested, I removed the routes_pathname_prefix in the dashGAF.py. Now when I visit 144.etc.etc.etc/dashGAF, I can successfully load a page. However, it is not the dash tutorial I'm expecting, rather it has a title "Dash" but the page contents are empty with just "Loading ..." on it.

As an aside:

  • How does mod_wsgi know where my actual dashboard python script /home/ubuntu/dashboards/dashGAF.py sit, if the <Directory ...> directive is not set? Does it get it solely from the *.wsgi file, when it's added to the system path?
  • Should I restart/reload the apache server for changes to the *.wsgi file or the actual *.py file? What do you recommend?

@GrahamDumpleton
Copy link
Owner

It relies on:

sys.path.insert(0,"/home/ubuntu/dashboards/")

Usually you wouldn't not include that though and would instead use:

python-path=/home/ubuntu/dashboards

option to WSGIDaemonProcess directive.

Usually you would not set the home option as you have. It results in the working directory being changed for the process to that directory, and also adds it is sys.path as well.

Either way, your code shouldn't rely on accessing files via a relative directory, but calculate absolute paths, which is why should rely on home if you were.

As to why it just says loading, not sure. Open the browser developer console and see if there are error messages there, or in the network tab of browser developer console see what assets couldn't be downloaded for the page.

@dgwyther
Copy link
Author

G'day Graham,
Fantastic, I've managed to get it loaded! Your suggestion of looking at the browser dev console was spot on. I saw a dash_renderer error, which led me to this link with the advice to add a request_pathname_prefix to the dash.Dash line in the python file.

Thank you for solving the problems, Graham - much appreciated.

Would you mind giving me a suggestion for how I should I set up my wsgi sites, if not having the *.wsgi inside the /var/www directory?
At the moment, this is my directory structure:
/var/www/html/wsgi/dashGAF.wsgi
/home/ubuntu/dashGAF.py

  • Also, should I remove one/either of the sites-enabled or sites-available config files?

Thanks again. I really appreciate the prompt advice.
Cheers
Dave

@GrahamDumpleton
Copy link
Owner

The sites-available file is the real one and which you should edit. The one in sites-enabled is supposed to be a symlink to the one in sites-available. The symlink would usually be created for you by a2ensite command when enabling a site.

As to config, you could have skipped the .wsgi file in /var/www/html and used:

WSGIDaemonProcess dashGAF user=ubuntu group=ubuntu home=/home/ubuntu threads=5
WSGIScriptAlias /dashGAF /home/ubuntu/dashGAF.py

WSGIProcessGroup dashGAF
WSGIApplicationGroup %{GLOBAL}
WSGICallableObject server

<Directory /home/ubuntu>
<Files dashGAF.py>
Require all granted
</Files>
</Directory>

@dgwyther
Copy link
Author

OK. So you configure the dash.conf file to point to the python script instead. I imagine this could lead to problems however if I have several python files in the /home/ubuntu/dashboards/ directory?

I encountered another issue with wsgi not finding a file (IOError: [Errno 2] File SensorStats.dat does not exist:...). But I changed my call in the python script from a relative path to an absolute path (e.g. /home/ubuntu/dashboards/SensorStats.dat) and it's loading nicely!

Thank you SO much for all your help. Please feel free to add an answer on SO and I'll accept it. (If you don't have enough time, I can answer my own question with all of the steps you suggested, etc.)

@dgwyther dgwyther closed this as completed Jul 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants