Ever wondered how you can deploy Dash(Plotly) on an Apache2 Server? With this article i want to guide you through this journey. As many others, Apache2 is a Webserver where you can publish your own websites and so your dash-app. Dash is a framework to create beautiful dashboards in python. By following the link below you can see a bunch of projects where dash has been used.
https://dash-gallery.plotly.host/Portal/
Dash is coming with a tiny webserver itself. This webserver is for development only. Due to security i cannot recommend using it for production and so does the dash developer. During development i use virtualenv to isolate the environment and use different dash and python version apart from the regular server. Once i have finished development and started deploying my app, i copied that folder to /var/www/html/ and with it the virtual environment.
cp -p /<path>/Dash /var/www/html/Dash
For apache2 you need to install some requirements to make dash proper working. This differs from your python version. For python3 install libapache2-mod-wsgi-py3
sudo apt-get install libapache2-mod-wsgi-py3
See this link, if you don’t know what wsgi exactly is: http://wsgi.tutorial.codepoint.net/
In short wsgi is an interface specification by which server and application communicate. I put my wsgi file in /var/www/html/Dash/wsgi.py.
#cat wsgi.py import sys sys.path.insert(0,"/var/www/html/Dash/") from app import server as application
Please note that app in “from app import server as application” is my file name. You might have a different name with your dash-code.
Configure Apache2
Further we need to modify our Apache2 configuration. There are several ways to deploy dash with Apache2. I like to use a different Port for my app. For now Apache2 is listening on Port 80/443 only. We need to add another Port like 8050. Amend ports.conf in /etc/apache2/ and add a second “Listen” line like below.
#cat ports.conf # If you just change the port or add more ports here, you will likely also # have to change the VirtualHost statement in # /etc/apache2/sites-enabled/000-default.conf Listen 80 Listen 8050 [...]
Once done we can create a new site on Apache2. Create a new file within /etc/apache/sites-available/. I named mine dash.conf but this is up to you.
#user@server:/etc/apache2/sites-available# cat dash.conf <VirtualHost *:8050> ServerAdmin webmaster@localhost DocumentRoot /var/www/html/Dash ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined WSGIDaemonProcess Dash threads=5 user=www-data group=www-data python-path=/var/www/html/Dash python-home=/var/www/html/Dash/bin WSGIScriptAlias / /var/www/html/Dash/wsgi.py <Directory /var/www/html/Dash> <Files wsgi.py> #Require all granted AuthType Basic #required for Authentication AuthName <name> #required for Authentication AuthUserFile "/<path>/.htusers" #required for Authentication Require valid-user #required for Authentication </Files> WSGIProcessGroup Dash WSGIApplicationGroup %{GLOBAL} Order deny,allow Allow from all </Directory> </VirtualHost>
*Please take into account that this file already contains the code for the Authentication in the next section.
WSGIDaemonProcess is running with user/group www-data, which usually is the group apache2 does work with. This is required to isolate apache2, mainly for security purpose.
Additionally we need to enable that site, so it gets recognized by Apache2
a2ensite dash
a2ensite will create a symlink in sites-enable to our configuration in sites-available.
As our WSGIProcess does run with www-data rights we have to give that group permission to access our dash folder with the correct privileges. Owner(root) does have full access while group(www-data) can read and execute. Others don’t have any permission for security reasons.
ls -ltr /var/www/html/ drwxr-x--- 9 root www-data 4096 Sep 28 15:28 Dash
You have to use command chmod respective chown to grant access to a folder/file. I had to do it as defined below, but it might differ in your case. “-R” stands for recursive execution.
chown -R :www-data Dash/ chmod -R o-rw Dash/
If you are not familiar with chown/chmod command read this post: https://www.unixtutorial.org/difference-between-chmod-and-chown/#:~:text=The%20chmod%20command%20stands%20for,a%20user%20and%20a%20group.
Dash Configuration
If you have come thus far, adapt your code and add “server = app.server”.
server = app.server if __name__ == '__main__': app.run_server(debug=True,host='0.0.0.0',port='8050')
Last but not least you have to release the port in your firewall. Iptables and ufw are the most common ones. In case you use Iptables execute following command in your shell.
iptables -I INPUT 3 -p tcp --dport 8050 -j ACCEPT
Everyone should be allowed to access your page now. Of course you can restrict it way more with IPtables-rules, I leave it to you. This is the simplest way publishing your site.
Secure your app with Basic Authentication
By default dash provides Basic authentication within the python code, but for some reason it does not work for me. The authentication screen prompts and i can enter my username/password but apache/dash won’t let me in. So i decided to create my own authentication by using htpasswd.
htpasswd -c -B <filename(ie. .htusers)> <username>
While executing it will ask for a password for this user. As soon as it has finished you can see your file. Link that one to your dash.conf, which was mentioned above.
That’s it. You finally set your apache2 up to run dash-apps. In my next article i am going to write about my dash-app and what it does.
Happy Coding so far 🙂
12 thoughts on “Deploy Dash with Apache2”
Great blog post, Stefan. Very clear explanations and instructions. Thank you for your contribution to the data science world :).
Thank you for your nice words, Adam :).
Dear Stevie,
I would like to execute in apache2 web server in ubuntu an script showing a simple graphic. I have followed your steps but when I try to execute the .py script I only get the code. Any idea what I’m missing? It is like it’s no been executed.
Thanks a lot for your guide and your help
Hi Xavier,
You may find an error code in /var/log/apache2/error.log if apache2 is trying to execute your python script. What python module is serving your graph? wsgi links your python code with apache, take this into account. You doesn`t need to execute your python script if apache was properly set up, curious why you mentioned you did so.
Might be helpful if you send me your shell history of your executions so far.
Best Regards
stevie
Dear Stevie,
I’m sorry I haven’t seen your answer before and thought you didn’t answer… I think I said “execute” the script when I should say “run”.
I’m still trying to run my dash/plotly script in apache2 webserver, but after following all your steps I can’t manage to make it work. I think I have all the needed libraries installed but I must have a misconfiguration error because I’m just getting the script code in plain text when I try to view the result of the script in the browser.
Is it possible to run the scripts in the 80 port as the other web applications? And without Authentication?
Thanks a lot for your help!
Hi Xavier,
you can skip the part with the authentication it is just optional.
If you want to run Dash on Port 80, you have to change the configuration a little. Either you change 000-default.conf or create a new site and disable your Virtualhost 80 in 000-default.conf.
Can you check if apache just prints the files content or if apache is serving your script as html? Did you use a virtual environment? If not you have to change python-home path.
what is the URI you are gonna use?
Bear in mind you have to consider your filename in your wsgi.py file. My dash-code is inside app.py so i used “from app import server as application” in my wsgi.py file.
I suspect wsgi to be the pain, as it links python with apache and it seems it doesnt for now.
Did you check your apache error.log?
Can you check if wsgi is enabled:
apache2ctl -M | grep -i wsgi
this command should result in “wsgi_module (shared)” or somewhat similar.
Best Regards
stevie
Hello,
I followed your tutorial but when I fill in the ip address of the server with the port (ip_adress:8050) I get the php page.
I tried to modify the content of dash.conf but in vain.
Would you have a solution?
Hi,
sounds like the virtual host doesn’t work properly, is the site enabled?
apache2ctl -S
Further check if that port is open by using a portscanner like Nmap
Have you had a look at your .htaccess? This file might contain a redirection to the main page.
Disable the default page with a2dissite and see if that might solve your problem.
Best regards
stevie
Hi, Thank you for your answer.
I managed to display something, an index of the files that are in the Dash folder.
I specify that I use a virtual environment. So I put : python-home=/var/www/html/Dash/venv/bin
I didn’t touch the rest.
I modify the .wsgi document to see, but without improvement.
If you have a lead?
Hi Legrand,
Have you set the required permissions on file and directories?
Please check your error.log file in /var/log/apache2. That file might contain the point you are doing wrong.
Try to use the root of your virtual Environments path for your python-home. \var\www\html\Dash
or
\var\www\html\Dash\venv
Not quite sure what your root folder of your virtual env is.
Best Regards
stevie
Hello Stevie,
thank you very much for the post!
I tried following this but was only able to attain an invalid command “WSGIDaemonProcess” error.
I’ve used pip install mod_wsgi, made sure to load it into the apache httpd.conf file as well so it should be installed and loaded – however I am unable to get it to work. Any suggestions?
Hi Jonas,
if you are using python3 pip3 is worth a shot and so is “sudo a2enmod wsgi” to check if wsgi is active.
As soon as wsgi is installed you must have these files:
/etc/apache2/mods-available# ll wsgi.*
-rw-r–r– 1 root root 5055 Feb 18 2020 wsgi.conf
-rw-r–r– 1 root root 60 Feb 18 2020 wsgi.load
and when it is activated:
/etc/apache2/mods-enabled# ll wsgi.*
lrwxrwxrwx 1 root root 27 Apr 1 2021 wsgi.conf -> ../mods-available/wsgi.conf
lrwxrwxrwx 1 root root 27 Apr 1 2021 wsgi.load -> ../mods-available/wsgi.load
dont forget to restart apache 🙂
Regards
stevie