Alibaba Cloud Tech Share - How to deploy Flask + WSGI + Nginx on Alibaba Cloud - Alibaba Cloud Developer Forums: Cloud Discussion Forums

Charlene
Assistant Engineer
Assistant Engineer
  • UID626
  • Fans1
  • Follows1
  • Posts53
Reads:2743Replies:0

Alibaba Cloud Tech Share - How to deploy Flask + WSGI + Nginx on Alibaba Cloud

Created#
More Posted time:Jan 22, 2017 15:43 PM
This year, I bought an Ubuntu 1.4 32-bit Alibaba Cloud server, and so far, I'm very satisfied with its performance.
Since using Linux, I have gradually turned my interest from all-in-one development frameworks and software to some others with more simplicity, performance and productivity. So, my preferred choices are now Python and Coffee for programming languages and AngularJS (frontend) + Flask (backend) for the development framework. This article explains how to resolve the last-kilometer problem for Flask, namely Linux deployment.
The deployment scheme is as follows:
• Using uwsgi host Flask for the web server
• Referring to uwsgi with Supervisor as the common startup service
• Implementing reverse proxy based on nginx
First of all, the Alibaba Cloud server supports remote connection by using SSH commands on this terminal.
ssh root@cloud server address
You can perform any operations as if on the local terminal after entering the password to log in to the server.

Install a Python environment
Next, you need to install a Python environment, Given that Python 2.7 is pre-installed with the default Ubuntu environment, you simply need to install the pip installation tool for Python. The pip tool is used to install certain software tools for Python-based apps, and you will see it frequently in the following sections.

PIP
If you want to use Python but know little about [pip|http://pypi.python.org/], please visit the following address to learn more:
sudo apt-get install pip
VirtualEnv
Different projects may reference different dependent packages. To prevent "dependency hell" resulting from conflicted versions and apps,
[Virtualenv | https://virtualenv.readthedocs.org/en/latest/] is required for Python projects. You can create a separate development environment using VirtualEnv for each Python app. Specifically, Virtualenv allows you to:
• Install new suites without required permissions.
• Use different versions of suites for different apps.
• Upgrade suites without affecting other apps.
Follow the steps below to install it:
sudo pip install virtualenv
After installing VirtualEnv, run virtualenv [directory name] in the project directory to create a virtual environment folder, and then run the activate command to start the created Python virtual environment. For details, see the following:
Assume that the project directory is /home/www/my_flask. First, install a virtual environment (where I used to name the virtual environment directory venv).
my_flask root$ virtualenv venv

>> New python executable in venv/bin/python
>> Installing setuptools, pip...done.

After the installation is complete, a new venv directory is created under the project directory and it contains the basic tools, commands and packages for running Python. Then, start the environment and enter the virtual environment using current command lines. Once you enter the environment, packages and references for any Python installation operations will be encapsulated into the virtual environment without affecting the overall Python environment.
my_flask root$ source venv/bin/activate

(venv)my_flask root$

After calling the activate command, you can see a text like "(venv)" before the command prompt. You can log out of the virtual environment by running the "deactivate" command.

Install uWSGI
In fact, mature Flask production and runtime environment choices are not that many and the top choices are [Gunicorn|http://gunicorn.org/] and [uWSGI|https://github.com/unbit/uwsgi]. It is said that configuring Gunicorn is easy but I have never made it. So, uWSGI is used instead. Next, you need to install uWSGI.
(venv)my_flask root$ pip install uwsgi
In the virtual environment, you do not have to run sudo as VirtualEnv has no permission requirements.
The installation can be completed in seconds. After the installation is complete, you can leave uWSGI behind but first transfer the crucial Flask environment and project files to server directories.

Install Flask
By using an inventory file, you can install Flask and its dependent packages all at one time. The used reference list is as follows:
requirements.txt
Flask==0.10.1
Flask-Login==0.2.11
Flask-Mail==0.9.1
Flask-Moment==0.4.0
Flask-PageDown==0.1.5
Flask-SQLAlchemy==2.0
Flask-Script==2.0.5
Flask-WTF==0.10.2
Flask-Cache==0.13.1
Flask-Restless==0.15.0
Flask-Uploads==0.1.3
Jinja2==2.7.3
Mako==1.0.0
Markdown==2.5.1
MarkupSafe==0.23
SQLAlchemy==0.9.8
WTForms==2.0.1
Werkzeug==0.9.6
html5lib==1.0b3
itsdangerous==0.24
six==1.8.0
awesome-slugify==1.6

Looking at the list, you can see the necessity of installing listed items with an inventory file all at one time or you have to install them one by one.
Before installing the inventory file:
(venv)my_flask root$ pip install -r requirements.txt
Ensure that the Python virtual environment is active or the inventory file will be installed somewhere outside the environment.
Upload Project Files
Next, you need to upload Flask project files. Based on the materials that I found from various "reproduction experts", they have simply added a standard Flask runtime file for this step. In fact, doing so for example purposes is rational but it is still a bit confusing. Why? Let's look at example code from them:
from flask import Flask
 
app = Flask(__name__)
 
@app.route("/")
def hello():
    return "Hello World!"

From the code, you can see that it's almost impossible to use this entry-level Flask example code in actual production environments. For my Flask project, I encapsulated the app in a package, which is common for many other developers, and compiled a manage.py file as the startup file by using Flash Script. In this way, you can better support different projects including installing to FastCGI under Windows environments.
The code of the manage.py file is as follows:
#!/usr/bin/env python
import os

if os.path.exists('.env'):
    print('Importing environment from .env...')
    for line in open('.env'):
        var = line.strip().split('=')
        if len(var) == 2:
            os.environ[var[0]] = var[1]

from app import create_app
from flask.ext.script import Manager, Shell

#Create an app through configuration.
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)

def make_shell_context():
    return dict(app=app)

manager.add_command("shell", Shell(make_context=make_shell_context))

@manager.command
def deploy():
    """Run deployment tasks."""
    pass

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

In this way, you can run Flask as follows:
python manage.py runserver
For more details, please refer to the [Flask Script|http://flask-script.readthedocs.org/en/latest/] extension.
To upload Flask project files to the server, you can use an FTP tool supporting SSH. The structure of complete project files is as follows:
www/
└── my_flask  
│   ├── logs
│   └── venv  //This is the virtual directory.
│   │   ├── bin
│   │   │         ├── activate
│   │   │         ├── easy_install
│   │   │         ├── gunicorn
│   │   │         ├── pip
│   │   │         └── python
│   │   ├── include
│   │   │          └── python2.7 -> /usr/include/python2.7
│   │   ├── lib
│   │   │         └── python2.7
│   │   ├── local
│   │   │         ├── bin -> /home/shenye/shenyefuli/bin
│   │   │         ├── include -> /home/shenye/shenyefuli/include
│   │   │         └── lib -> /home/shenye/shenyefuli/lib
│   └── app  //This is the Flask program directory.
│   │           └──  __init__.py //This is the program package file. This directory contains other files, which are not detailed in this document.
│   ├── manage.py  
│   ├── requirements.txt


Configure uwsgi
So far, project preparation is complete and you can now proceed to configure uwsgi. For detailed commands for configuring uwsgi, please refer to the official documentation. In this document, the startup configuration method is used as an example. Specifically, create a confg.ini file (see the following for its content) in the project directory.
(venv)my_flask root$ uwsgi config.ini
I personally think this is the easiest way for configuring uwsgi and you can also modify the configuration file whenever you need. The content of the config.ini file is as follows:
[uwsgi]

#This indicates the address and port used during uwsgi startup.
socket = 127.0.0.1:8001

#This points to the website directory.
chdir = /home/www/

#This is the Python startup program file.
wsgi-file = manage.py

# This is the application variable name for startup in the Python app.
callable = app

#This indicates the number of processors.
processes = 4

#This indicates the number of threads.
threads = 2

#This is the status detection address.
stats = 127.0.0.1:9191

Note: For callable=app, app is a variable in the manage.py file and its type is the application class for Flask.
Run uwsgi.
```
(venv)my_flask root$ uwsgi config.ini
[uWSGI] getting INI configuration from config.ini
*** Starting uWSGI 2.0.8 (64bit) on [Fri Dec 19 14:34:11 2014]
//Unnecessary startup information is omitted here.
Stats server enabled on 127.0.0.1:9191 fd: 15 ***
```
Now, you have started uwsgi normally and loaded Flask project files. Then, press Ctrl+C to quit. So far, you have started Python app with commands. However, in actual operation environments, you also need to configure the app so that it can start up along with the server and run as a background service. Therefore, you also need to install another tool to boot uwsgi.

Install Supervisor
By using [Supervisor|http://supervisord.org/configuration.html], you can start multiple apps at one time. Most importantly, when an app crashes, it can restart automatically to ensure constant availability.
sudo apt-get install supervisor
The global configuration file for Supervisor is located in:
/etc/supervisor/supervisor.conf
You normally do not need to make any changes to the file but simply add a new *.conf file and place it under
/etc/supervisor/conf.d/
To do this, create a new supervisor configuration file (and name it my_flask_supervisor.conf) to start the uwsgi of the my_flask project:
[program:my_flask]
#This is the startup command entry.
command=/home/www/my_flask/venv/bin/uwsgi /home/www/my_flask/config.ini

#This is the directory where the command-line program resides.
directory=/home/www/my_flask
#This is the username for running commands.
user=root
        
autostart=true
autorestart=true
#This is the log address.
stdout_logfile=/home/www/my_flask/logs/uwsgi_supervisor.log

Starting the Service
sudo service supervisor start
Stopping the Service
sudo service supervisor stop

Installing nginx
[nginx|http://nginx.com/] is a reverse proxy software program featuring lightweight, high-performance, low resource occupation and high concurrency web services.
sudo apt-get install nginx

Configur nginx
Configuring nginx on Ubuntu is also very simple as you do not need to modify the default nginx.conf file but replace the
/ext/nginx/sites-available/default
file.
Create a new default file:
server {
      listen  80;
      server_name XXX.XXX.XXX; #Internet address
    
      location / {
        include      uwsgi_params;
        uwsgi_pass   127.0.0.1:8001;  #Point to the internal address used by uwsgi and forward all requests to uwsgi to process.
        uwsgi_param UWSGI_PYHOME /home/www/my_flask/venv; #Point to the virtual environment directory.
        uwsgi_param UWSGI_CHDIR  /home/www/my_flask; #Point to the website root directory.
        uwsgi_param UWSGI_SCRIPT manage:app; #Specify a startup program.
      }
    }

Replace the default configuration file and the configuration is complete.
Be sure to restart nginx after changing the configuration file:
sudo service nginx restart

Summary
The Alibaba Cloud server features high performance. With the high-performance Flask+uWSGI+Nginx architecture, the entire website provides a high responsiveness and the response speed for each page is less than 100ms. Comparatively, on the website (same app but programmed in another language) programmed in C# that is deployed on Avarix, the response speed of each page is at least 2 seconds. I hope this article can help readers to improve the performance of their websites.
Guest