Skip to main content

Notes on setting up web host with Python Flask

☝Introduction

We follow the tutorial given in Ref. [1, 2] for setting up the web host using Python Flask module. Details will not be reproduced in current blog step by step. Instead, we will focus on 1) some key aspects to make step description clearer and 2) steps where error can easily occur.

First, we give all the necessary recipes, as follows,

  • Flask - Python web server
  • uWSGI - Sitting in the middle between Flask and Nginx for connection purpose.
  • Nginx - Facing outwards to receive request.
and we will configure the web host on CentOS 7.

Traditionally, we have the web server hosts files in specific location on the server (e.g. /var/www) and then we will have, e.g. the Apache HTTP server to listen to user request (through a certain port, e.g. 80) and fetch certain files stored in specific location on the server and then send back to users' browser. When using Python to set up web host, we have one more layer for the connection between files on the server to be visited and users. The idea is that Python is responsible for creating contents, uWSGI is responsible for 'translating' and Nginx is responsible for receiving from users for request and sending back to users the 'translated' contents.


Preparation

On CentOS 7, Nginx can be installed with yum,

sudo yum install nginx

Sometimes, it may also be necessary to install pip and python-devel if they are not already [3, 4],

sudo yum install python-pip python-devel

With Python 3, we may need to change the command to [5, 6, 13, 14],

sudo yum install python3-pip python37-devel

(here we take Python 3.7 as an example).

It is always recommended that we should create dedicated environment when setting up the web host with Python. Therefore, either we can follow the instruction given in Ref. [1, 2] to install and set up virtual Python environment using virtualenv using pip. Or we can use conda to set up the dedicated Python environment. Within the created environment, we can either use pip or conda to install necessary packages, namely uwsgi and flask. In some cases, using pip to install uwsgi may return error, where one has to use conda to install it.

N.B. Though the packages are installed within certain environment (which seems not accessible from outside the environment), they can still be accessed from outside - the reason simply is that when a specific version of Python is used in question (e.g. that within a certain environment), all the packages installed within the corresponding environment will become available.

A simple start

With just Flask installed (no Nginx, no uWSGI), one can already host a web - that's why we call Flask a Python web server, since simply with it we can just host a web server! Refer to Ref. [1, 2] for a Hello World demo with a simple Python script.

Create the WSGI entry point

Now we go a bit further to start the web host through WSGI entry point. According to Ref. [1, 2], the entry point here is just a simple Python script which first imports the Python method (containing the Flask app) and then run it. In Ref. [1, 2], the entry point script and the main Python app script are put together under the same directory. But in practice, we don't have to do that - the import command in the entry point script should specify where to find the main app script.

N.B. By default, uwsgi expects application as our app name. If we want to use another name for the app (specified in the main app Python script), we should specify the callable app name [7, 8]. When starting the uWSGI service directly from command line, we should have,

uwsgi --socket 0.0.0.0:8000 --protocol=http --callable myapp -w run

where myapp is our app name and run is the entry point script stem name.

N.B. We should not use port 80 in the entry point script [9].

Setting up uWSGI as a system service

We don't want to just stay with starting the web server directly from command line since once we close the SSH connection to our server, the web hosting will stop. Though we can use service like tmux to run our web host in the background without being disturbed by SSH connection closure, that's still not an ideal solution. Following Ref. [1, 2], we can set up a system service for our web hosting, which we can then enable to start automatically with the system. Not only that, but also it allows us to better control and manage the web host - start & stop service, check status and running logs, etc.

Without going into details, in brief we need to create two files for such a purpose - one is the uWSGI configuration file which contains some parameters concerning the uWSGI service and also points to the entry point Python script mentioned above. The other one is the system service file which basically tells the OS what we intend to serve. Not mentioning other straightforward information, the WorkingDirectory and ExecStart entries together tells the system service where our uWSGI configuration file is located. Meanwhile, the Environment entry tells which bin directory we want to use - recalling, at the beginning, we mention that we don't need to worry about the Python modules being installed within environment - here by specifying which Python we want to use, all the necessary modules can be fetched automatically.

Configuring Nginx

The last step is to configure Nginx - to establish the connection between outside world and our Python app (through uWSGI as the interface as discussed above). To do this, again we should follow steps in Ref. [1, 2] and details won't be reproduced here. One critical parameter to mention is the location of the socket file - this file is like a junction between Nginx and uWSGI and therefore in the configuration files of both, the socket file should be with exactly the same name.

Another potential issue to mention here is that, though Ref. [1, 2] mentions some file/folder permission configuration concerning setting up Nginx, in practice we may still have issues establishing the connection. The common problem is 502 bad gateway issue. Once this occurs, we can consider the following potential solutions,
  • Open port in firewall configuration. In CentOS 7, this may require the installation of firewalld package and following the instruction given in Ref. [11] for how-to.
  • If web server is within a certain organization network, we may need to check the firewall restriction of the organization network as well. Specifically for CADES service at ORNL, we need to follow the instruction in Ref. [12] for how-to.
  • We may want to disable SELinux, according to the comments in Ref. [1, 2].
plus those mentioned in Ref. [1, 2].

-------------------------------------------I AM A SEPARATOR-------------------------------------------

Notes on setting up pdfitc on CADES hosted at ORNL
  • We want to follow Long's instruction in Ref. [15] for step-by-step procedures (see the 'How to install' section). We want to skip step-#5 and also for step-#7, the file we want to configure for implementing GSAS II is 'run_gsas2_calc.py' under 'pdfitc' folder. The line we want to change is the one containing 'sys.path.insert'.
  • The folder cloned from Long's 'tsitc' repository is not complete - some files and folders are missing which will cause the app not starting. We need to back up Long's working version to a separate repository and develop from there (need to post the new repository here once it's done).
  • For running the pdfitc service (edit '/etc/systemd/system/pdfitc.service' file if changes to the service are needed) for the first time, we may encounter problems about modules not found. Usually, the missing modules (e.g. dash) should be straightforward to install with, e.g. conda.
  • The 'celery.task' method has been deprecated and therefore is no longer available with celery. Accordingly in the main 'app.py' file, we want to comment out the import line for 'celery.task' and change 'revoke' to 'app.control.revoke' [16, 17].
References

Comments