Serving Flask Apps with NGinx and Uwsgi

Even an embedded system is going to need a web application, be it on the embedded device, or a part of a test system.

We recommend flask applications, and serving them via Nginx and uWSGI.

There are a lot of examples online. The following one outlines most of the possibilities you can choose from: deploy-flask-uwsgi-nginx

We recommend using the apps-available and apps-enabled as the method for starting your uwsgi server flask application. This is less intrusive and requires less custom parts like an additional system specific service.

For additional security you could install your applications somewhere other than /var/www if that is being served as your root for nginx (for example use /srv/uwsgi-apps instead).

To ensure independent application environments, us a python virtual environment for each of your applications. If you do choose to use the system libraries, we touch on some issues you may run into.

For the nginx configuration, the default uwsgi socket location for your application can be used. On Ubuntu at least it has been:

uwsgi_pass unix:/run/uwsgi/app/<your-application>/socket;

Trouble Shooting

To help you trouble shoot during setup, once you have defined <yourapplication>.ini file under /etc/uwsgi/apps-available and symlinked to apps-enable, restart uwsgi and then tail the uwsgi log for your application.

sudo systemctl restart uwsgi
sudo tail -f /var/log/uwsgi/app/<yourapplication>.log

If something goes wrong inside your application on (re)starting uwsgi, that log will show it.

For example

- mapped 654912 bytes (639 KB) for 8 cores
- *** Operational MODE: preforking ***
Traceback (most recent call last):
  File "./wsgi.py", line 1, in <module>
    from app import app as application
  File "./app.py", line 1, in <module>
    from flask import Flask, jsonify, request
ModuleNotFoundError: No module named 'flask'
- unable to load app 0 (mountpoint='') (callable not found or import error)

Module Not Found Error: No module name

In the example above either the system (or your virtual environment) does not have flask installed or you are using the wrong python plugin.

If your python –version is 3.6.x the python plugin in your uwsgi .ini file should be

plugin = python36

When you run uwsgi through its apps-enabled/<yourapp>.ini method, the application will not be run as your user, so even if you have installed flask and other libraries using pip(3), they are attached to your user’s local, rather than the system library.

If you install using pip a library you will see the output.

Requirement already satisfied: flask in /home/user/.local/lib/python3.6/site-packages

Note the /home/user/.local.

If you are not using a virtual environment, you need to ensure libraries are system libraries, either install them using their corresponding distribution package (e.g. in Ubuntu, sudo apt install python3-flask, or using sudo -H pip …)

No Python Application Found

If you see the error

--- no python application found, check your startup logs for errors ---

Then look earlier in the application log (/var/log/uwsgi/app/<yourapplication>.log) to see if your application was started or if their was an exception.

Unable to load app

unable to load app 0 (mountpoint='') (callable not found or import error)
*** no app loaded. going in full dynamic mode ***

To decipher this, look into <yourapplication>.ini file for the module and chdir lines

chdir = /srv/uswgi-apps/yourapplication
module = wsgi:myapp

The wsgi of wsgi:myapp must correspond to the file name wsgi.py in your /srv/uwsgi-apps/yourapplication folder and the myapp must correspond to the import line in your wsgi.py file which imports your flask app as ‘myapp‘. In the example here, the flask app file was called app.py (as many tutorials tend to name their app files).

from app import app as myapp

if __name__ == '__main__':
    myapp.run()

Gracefully Reloading Applications

The uWSGI documentations detail how to manage your applications once deployed.

We recommend using at least the touch reload option and for finer grain control the Master FIFO method.

Touch Reload

The touch reload means that any time you change your ini file, that application will be reloaded.

touch-reload = /etc/uwsgi/apps-available/<yourapplication>.ini

DANGER! If using touch reload, verify your .ini changes on a staging server before deploying to a production server, because your application will be down if there is an error loading it.

Master FIFO

You can have one or more master-fifo lines.

master-fifo = /tmp/<yourapplication>-master-fifo

From the uwsgi docs: Only the uid running the master has write access to the fifo.

This means that most likely you need to echo commands to the master fifo as the www-data user (unless you specify a different user using uid in .ini file).

$ sudo -u www-data sh
[sudo] password for user: 
$ echo r > /tmp/<yourapplication>-master-fifo

HUP System Signal

If you already deployed your application and you are not in a position to add touch reload or master fifo, you can use the -HUP signal to reload your application.

sudo kill -HUP $(cat /var/run/uwsgi/app/<yourapplication>/pid)