Deploying Flask Application using Apache with mod_wsgi
Introduction
We have written this blog to help developers deploy flask
application with apache
and mod_wsgi
in production.
We read through a lot of articles and found out the steps we layout below are the simplest way to deploy.
Also, the biggest caveat to deploying in production is version mismatches, so we are going to be building things from source rather than using apt-get to install packages.
So let’s get started.
Build and install custom version of python
We used python 3.7.5
for a current project and here is how you can deploy python from source. Make sure you remove any other python version you might have on your machine.
To remove any existing python installations.
sudo apt-get purge python<version>
sudo apt-get autoremove
1. Install Dependencies and packages.
sudo apt update
sudo apt install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libsqlite3-dev libreadline-dev libffi-dev wget libbz2-dev
2. Download source
Now to fetch tar file for a specific python version use.
wget https://www.python.org/ftp/python/3.7.5/Python-3.7.5.tgz
You can check out other python versions here: Link
3. Compile python
Now to compile the downloaded tar.
tar -xf Python-3.7.5.tgz
cd Python-3.7.5
./configure --enable-shared --prefix=/usr/
make -j4
sudo make install
Argument in make -jN
is the number of processors if you are not sure about number of processors in the machine. You can use
nproc
to get it.
Build and install custom version of wsgi mod
Ok, now we move on to getting mod_wsgi installation right. Before we get into steps I would like you to read this Link. which essentially says this:
The problem in trying to force mod_wsgi to use a different Python installation than what it was compiled for,
even where it is the same Python version, is that the Python installation may itself not have been
compiled with the same options. This is especially a problem when it comes to issues around how Python stores
Unicode characters in memory.
So to avoid this problem we are going to build mod_wsgi from the source and compile it with python we just installed in the last step.
1. Compile wsgi-mod
Download source code from: Github releases
tar xvfz mod_wsgi-X.Y.tar.gz
cd mod_wsgi-X.Y
sudo apt-get install apache2-dev
./configure --with-python=/usr/bin/python
make -j4
sudo make install
Configure Apache
Ok, now we move on to building apache2.
1. Install apache2
sudo apt-get install apache2
2. Configure Wsgi module
Now we need to configure apache with the mod_wsgi we complied and installed in the last step.
Create a file: `/etc/apache2/mods-available/wsgi.load`
Add the following line to the file:
`LoadModule wsgi_module /usr/lib/apache2/modules/mod_wsgi.so`
Now we need to enable mod_wsgi and restart apache2.
sudo a2enmod wsgi
sudo systemctl restart apache2
This completes the installation of Apache2 and mod_wsgi, all complied with python3.7.5
.
Deploying Flask Application
1. Create .wsgi file
Now to deploy the flask application copy your code directory to
/var/www/
directory and create <your_application>
.wsgi file and add the following lines.
import sys
sys.path.insert(0, '/var/www/<your_application_dir>')
from <your_application> import <flask_app> as application
2. Create virtualenv
Its generally best practice to create a virtualenv for your application and install all the dependencies, to avoid clashing package versions that other application might be using. To create a virtualenv:
cd /var/www/
virtualenv -p python3 <venv_name>
pip install -r requirements.txt
Note that you will need a requirments.txt
file. To create one you can do the following:
pip freeze > requirements.txt
3. Create Configuration file in Apache
Now we need to create a configuration file to tell apache from where to load your application.
In /etc/apache2/sites-available
create <your_application>.conf
file and add the following lines.
<VirtualHost *:80>
ServerName <Server_name>
WSGIDaemonProcess <your_application> user=<user> group=<group> threads=5 \
python-home=/var/www/<venv_name>
WSGIProcessGroup <your_application>
WSGIApplicationGroup %{GLOBAL}
WSGIScriptAlias / /var/www/<your_application_dir>/<your_application>.wsgi
<Directory /var/www/<your_application_dir>/<your_application>/>
Order allow,deny
Allow from all
Require all granted
</Directory>
Alias /static /var/www/<your_application_dir>/<your_application>/static
<Directory /var/www/<your_application_dir>/<your_application>/static/>
Order allow,deny
Allow from all
</Directory>
ErrorLog /var/www/<your_application_dir>/error.log
LogLevel debug
CustomLog /var/www/<your_application_dir>/access.log combined
</VirtualHost>
You can remove that logging commands if you don’t wish to see logs.
4. Enable application
Now we need to tell apache to enable our application and load the configuration file we just created.
sudo a2ensite <your_application>
sudo systemctl restart apache2
That’s it. Your website is up and running on the public IP for the server.