I still get questions from time to time about how to deploy a python web application using Apache and not NGINX. Here is a quick tutorial to deploy your Flask application on Ubuntu 16.04 or any linux distribution (considering relevant changes) using Apache, Gunicorn and systemd. Until some weeks ago I used supervisord instead of systemd but nowadays I prefer to use systemd because is already there, installed, part of system. And also the reason to look into systemd and to switch was that I had to deploy an application on SLES (SUSE Linux Enterprise Server) and there is no supervisord package available in repos.

Note: This is a very basic configuration to get everything running. It is just for learning and to get the idea how everything is connected.

So, let's start:

we create a user which will run our Flask application

# adduser flaskappuser

install and configure apache:

# apt-get install apache2

As result we should get the default apache webpage in browser (http://your-ip-here)

Add our application to apache web server config file. Add the following lines (inside VirtualHost block) to /etc/apache2/sites-available/000-default.conf. Make a backup of this file before you modify it

<VirtualHost*:80>
# The ServerName directive sets the request scheme, hostname and port that
# the server uses to identify itself. This is used when creating
# redirection URLs. In the context of virtual hosts, the ServerName
# specifies what hostname must appear in the request's Host: header to
# match this virtual host. For the default virtual host (this file) this
# value is not decisive as it is used as a last resort host regardless.
# However, you must set it for any further virtual host explicitly.
#ServerName www.example.com
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
<Proxy*>
Order deny,allow
Allow from all
</Proxy>
ProxyPreserveHost On
<Location"/flaskapp">
ProxyPass "http://127.0.0.1:5000/"
ProxyPassReverse "http://127.0.0.1:5000/"
</Location></VirtualHost>

restart apache to see if is working:

# service apache2 restart

http://your-ip-here —> should give you the same standard html page for apache, as before

http://your-ip-here/flaskapp —> should give you:

Service Unavailable
The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.

that’s because we still don’t have our Flask app running, but it seems that apache is trying to send the request to it, good.

make sure that everything in flaskappuser home directory belongs to this user

# chown -R flaskappuser:flaskappuser /home/flaskappuser/

Now we have one more step. We want to monitor our Flask app and to restart it on crashing or to have nice start/stop commands for it. Or to have it started automatically on reboot. In order to do that we can use systemd which is available already in Ubuntu 16.04.

For that we have to create a .service file for our app. Here is my file: (/etc/systemd/system/flaskapp.service):