Flask is a Python based micro-framework, which can be used to create dynamic websites, APIs, and many other applications.
Despite all Linux cloud options you might have a customer with a Windows environment, that would rather use their existing system than setting a Linux one. No problem, right? But how do we deploy a Flask app to production Windows?
As I faced many issues when I had this challenge, I thought listing the steps and some of the problems would be a good topic for my first post on Dev.to.
The official deployment documentation states "Flask’s built-in server is not suitable for production as it doesn’t scale well", so you need a WSGI server to deploy your Flask application to production.
I will start using Apache + mod_wsgi, and later add more posts to the series covering other options.
Flask deployment on Windows using Apache and mod_wsgi
1. Install Apache
Go with the recommended distribution from Apache Lounge. I downloaded version 2.4.43 Win64 as a zip file. There was a warning saying "Be sure you installed latest 14.xx Visual C++ Redistributable for Visual Studio 2015-2019", and they provide direct download links for it. Make sure to download the appropriate vc_redist
x64 or x86, matching the Apache version you got, in my case x64.
Install the vc_redist
and then unzip Apache to the default location C:\Apache24
. If you select a different location take note as we'll need it later.
To test Apache, open a command prompt, cd C:\Apache24\bin
. Then issue this command to start Apache:
httpd.exe
After you press Enter, it will tell you if there are any errors. Open a browser and go to http://localhost
. You should see a page saying "It works!". You can shut down Apache by pressing Ctrl+C
(it may take a few seconds).
The ReadMe.txt
file on Apache's zip file has more information and examples, including how to run it as a Windows service.
2. Install mod_wsgi
You need the mod_wsgi Python package as the middle man to show Apache how to handle Python applications.
Assuming you already have Python installed, mod_wsgi can be installed using pip install mod_wsgi
on the command prompt. However, some of its dependencies might make it tricky.
2.1 Apache location
If you didn't install Apache on the default location, you might get this error after the pip install mod_wsgi
:
RuntimeError: No Apache installation can be found. Set the MOD_WSGI_APACHE_ROOTDIR environment to its location.
If that's the case, use the set command. For example:
set "MOD_WSGI_APACHE_ROOTDIR=F:/Apache24"
Ensure you specify the path with a forward slash, like the example. This is only needed when doing the install.
2.2 Microsoft Visual C++ Build Tools
After that, if you try the pip install mod_wsgi
again, you might receive a long error, but the most important part is this one:
building 'mod_wsgi.server.mod_wsgi' extension
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual
C++ Build Tools": https://visualstudio.microsoft.com/downloads/
mod_wsgi will be compiled on your Windows host, so it has a dependency on Microsoft Visual C++ Build Tools. Note the Build Tools are different than the Redistributable that you installed on step 1.
Go to the Visual Studio download page, expand Tools for Visual Studio, and click the download link for the Build Tools (currently 2019). Execute the installer, select C++ build tools, on the right side you can un-check some optional features, but you need at least MSVC v142 and Windows 10 SDK.
After the install is complete you will have to reboot Windows.
Finally, try the pip install mod_wsgi
again and it should work.
If you still face errors, on the Start menu look for "Developer Command Prompt for VS 2019", and use it to issue the pip install mod_wsgi
. It will have the correct PATH with the VC++ Build Tools and should avoid setup issues.
3. Flask app setup
Assuming you already know Flask, and installed it on your Windows using pip install flask
, there a few considerations for structuring your app:
- The general recommendation is to set your app to act like a Python package, so create a folder containing at least a
__init__.py
with the main code. - Another option, is to use an empty
__init__.py
and the main code on another .py file on the same folder. - As a Python package, avoid using '-' on your folder name, otherwise you might face syntax errors when importing your app later. This StackOverflow question gives more details about it.
3.1 Sample app and structure
Here is the __init__.py
sample I used for this article:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello Flask under Apache!'
if __name__ == "__main__":
app.run()
Here is the project structure for this sample:
C:\git\
+-- yourapp
| +-- __init__.py
+-- wsgi_scripts
| +-- yourapp.wsgi
In this case my app 'package' is called yourapp.
3.2 Create your .wsgi file
To run your application you need a wsgi file. In my sample I have yourapp.wsgi
. Note that I stored this file on a separate folder. Storing the wsgi file on the same folder as you Flask app works as well, but is not recommended.
A minimal wsgi file (which is Python code):
import sys
sys.path.insert(0, 'C:\\git')
from yourapp import app as application
- The
sys.path.insert
should point to the location that contains the folder with your app. - Use double backslashes on your
sys.path.insert
.
4. Configure Apache httpd.conf
On the command prompt, issue: mod_wsgi-express module-config
, the output should be similar to:
LoadFile "c:/program files/python37/python37.dll"
LoadModule wsgi_module "C:/Users/prod_deploy/AppData/Roaming/Python/Python37/site-packages/mod_wsgi/server/mod_wsgi.cp37-win_amd64.pyd"
WSGIPythonHome "c:/program files/python37"
Copy the output and paste it on your C:\Apache24\conf\httpd.conf
. I suggest putting it after the existing LoadModule
directives.
At the end of the same httpd.conf
file, add:
# Include Flask file
Include conf/yourapp.conf
Replace yourapp
with the name of the configuration file you want to use. With this, we will have the Flask VirtualHost configuration on a separate file, avoiding mistakes.
5. Create the yourapp.conf
On your Apache install folder, navigate to the conf subfolder, e.g. C:\Apache24\conf
, and create the yourapp.conf
file.
A minimal sample file:
<VirtualHost *:80>
ServerName flaskwill.com
WSGIScriptAlias / C:/git/wsgi_scripts/yourapp.wsgi
<Directory C:/git/yourapp>
Require all granted
</Directory>
</VirtualHost>
- On VirtualHost, change 80 to a different port if needed.
- ServerName should list the server's IP address or a DNS name
- WSGIScriptAlias has two arguments, the first is the website path which will be associated with the wsgi file, in this example / or the root. The second argument is the absolute path to the wsgi file. In this example, when I access flaskwill.com/ it will execute my yourapp.wsgi.
- Directory should point to the folder with your Flask app files. Note the 'Require all granted' to give Apache (version 2.4 or later) access to the files and sub-folders. Older versions of Apache use a different syntax.
6. Start Apache and test your app
After covering all steps, start Apache (or restart it if already running), so it will read the conf files and load your app.
Open a browser and enter http://localhost
and your Flask app should show up. If you set a DNS address like the flaskwill I used, you will have to update the real DNS to point to your server, or you could update your Windows hosts
file to test it locally.
Closing
I hope this is useful for someone, but remember this is just one way of doing it, as I am sure there are other methods of deploying Flask.
I appreciate any feedback so I can improve this post and learn for the next ones.
Thank you for reading!
References:
https://flask.palletsprojects.com/en/1.1.x/deploying/mod_wsgi/
https://github.com/GrahamDumpleton/mod_wsgi
https://modwsgi.readthedocs.io/en/develop/index.html
http://httpd.apache.org/docs/2.4/
Top comments (16)
Hi William, thank you for the amazing article. I was facing a small issue with VHost.conf file in tag.
Error:
AH01630: client denied by server configuration: C:/git/wsgi_scripts/yourapp.wsgi
Solution:
It worked for me with
<Directory C:/git>
instead of<Directory C:/git/yourapp>
Also deploying it with flask there was an issue with few other packages like Pandas and Scikit-Learn where the flask was hanging.
So to solve this I added one line
WSGIApplicationGroup %{GLOBAL}
in httpd.conf under - ReferenceI also hope this helps others.
Thank you for the feedback and these other hints Shreyans!
Thanks Shreyans - I encountered an issue when just importing spacy in the flask app
adding WSGIApplicationGroup %{GLOBAL} fixed it
Also regarding the Error:
AH01630: client denied by server configuration:
Changing the directive from
to
worked for me.
Hi William,
I followed steps as you said..I am trying to diploy dash application. When i run server, webpage keeps running without any results. Any specific things needs to be considered?? Please help me on this.
Regards
Ganesh
Hello Ganesh, I am trying to deloy a dash application as well under wampserver stack ( it's a Web server stack package including apache). the app is not rendered, I still get "it works!" in the web page when I test it. I would like your guidance if you've managed to succesfully deploy it. Thanks.
Sorry Ganesh, I didn't get notified of your post. I'm not sure about "dash application", but I recommend that you check the Apache logs on C:\Apache24\logs , to see if any error was recorded.
Hi William, Thanks for the article. I am just having trouble booting up apache after adding the Config lines in httpd.conf file. Getting this in my error logs -
Fatal Python error: initfsencoding: unable to load the file system codec
ModuleNotFoundError: No module named 'encodings'
Already checked that Encodings module is present and python is correctly installed.
Can you please help?
Hi william,
Thanks for the great article. Although, I am stuck at a problem while executing command at step-4 i.e. "mod_wsgi-express module-config" in command prompt. It is throwing "failed to create process" error. I have also searched many articles on the internet but did not find the solution. Kindly guide me through this error, if you know this.
Thanks
Thank you William for this detailed article. I am a complete newbie trying to deploy a dash application (mainly a Flask app) in windows environment. I have apache server already set up under wampserver (in my understanding it's a Web server stack package including apache ). However, I followed the steps as if apache is not there yet. Now, after completion, the app test (localhost test) is still returning "it works!" instead of the actual app.
I am stuck at this point, I would appreciate any comment of suggestion.
PS1: the app was tested in localhost and it works perfectly
PS2: my team uses wampserver for integrating other tools and apps, so this choice is kinda out of my hand. However, I am open to any other suggestions to rectify this.
Thanks for the post.
Apache is robust but it doesn't support well socket communication on Windows.
Thank you for the feedback. I still need to learn more about Apache, are you saying it might face issues once it needs to handle multiple connections?
Hi William,
Can u plz tell how to update hosts file to test the app locally.
Hi deepank2596,
On Windows the hosts file is usually on C:\Windows\System32\drivers\etc . I believe it's a good idea to make a backup in case you make a mistake, and depending on your settings you might need admin access to edit the file. Once you edit it, you can add entries like this one:
127.0.0.1 willtest.com
It points to a fake address that I can type on my browser to simulate going to a real address. Besides that you can always use localhost on your browser to test the app locally.
Hi William,
after starting Apache, localhost shows just Forbidden site with error 403. Any advice?
I also get HTTP 403 Forbidden
EDIT: Change the
<Directory C:/git/yourapp>
to<Directory C:/git>
as described in the comment above.Thanks for sharing this William!