Publish Flask service application on ubuntu with Nginx and Gunicorn

This article introduces the use of Nginx and Gunicorn to publish Flask service applications on ubuntu. The original version of Ubuntu is 18, and my test environment is 20.

Learning link: https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-gunicorn-and-nginx-on-ubuntu-18-04

Prerequisites

The content of this article does not include the installation of nginx, you can refer to: Nginx installation on Ubuntu, testing

This article requires you to have a non-root user, but belong to the sudo group. If not, do the following under the root user:

  1. adduser sammy

  2. usermod -aG sudo sammy

installation

Do the following:

sudo apt update
sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools

Set up a python virtual environment

Install virtual environment program

sudo apt install python3-venv

Create a working directory: 

mkdir ~/myproject
cd ~/myproject

Create a virtual environment in the directory:

python3.6 -m venv myprojectenv

 The above is the operation of the original text. It may be because of ubuntu18. The version of python3 is 3.6 and the version of ubuntu20 is 3.8. So my operation is:

python3.8 -m venv myprojectenv

I estimate that it should be possible to directly python3 -m venv myprojectenv, otherwise you will have to check your python3 version. 

Before installing other applications, activate the virtual environment:

source myprojectenv/bin/activate

Install gunicorn flask in the virtual environment, do not use pip3 in the virtual environment, but pip

pip install gunicorn flask

Create a simple sample application

Build a very simple Flask application:

nano ~/myproject/myproject.py

The content of the file is:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1 style='color:blue'>Hello There!</h1>"

if __name__ == "__main__":
    app.run(host='0.0.0.0')

If there is a firewall, you need to set:

sudo ufw allow 5000

 Now start our application:

python myproject.py

You should see:

Output
* Serving Flask app "myproject" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

Type in the browser:

http://your_server_ip:5000

Be sure to replace your_server_ip above with the ip address of your host here. 

You should be able to see

 It shows that our simple Flask application is successful.

Establish WSGI entry point

Create a wsgi entry point file:

nano ~/myproject/wsgi.py

The content of the file is:

from myproject import app

if __name__ == "__main__":
    app.run()

Configure Gunicorn

First, we test the Gunicorn application:

cd ~/myproject
gunicorn --bind 0.0.0.0:5000 wsgi:app

You should see the output:

Output
[2018-07-13 19:35:13 +0000] [28217] [INFO] Starting gunicorn 19.9.0
[2018-07-13 19:35:13 +0000] [28217] [INFO] Listening at: http://0.0.0.0:5000 (28217)
[2018-07-13 19:35:13 +0000] [28217] [INFO] Using worker: sync
[2018-07-13 19:35:13 +0000] [28220] [INFO] Booting worker with pid: 28220

Like the test flask application above, enter the ip address and port number in the browser:

http://your_server_ip:5000

The output should be the same as above:

Exit the environment:

deactivate

Create a watchdog program below:

sudo nano /etc/systemd/system/myproject.service

 The content of the file is:

[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target

 It is assumed that the user name is sammy, and whether the environment directory is consistent, you need to make changes depending on the situation.

Here is an explanation of the ExecStart line:

Start 3 worker processes (should be adjusted as needed)
created in our project directory and bound to the Unix socket file myproject.sock. Set the umask value to 007 to create a socket file to grant owner and group access rights, while restricting other access rights.
Specify the WSGI entry point file name and the Python (wsgi: app) that can be called in the file

Now we start the service and enable automatic execution at startup.

sudo systemctl start myproject
sudo systemctl enable myproject

We check the running status:

sudo systemctl status myproject

There should be output similar to the following:

Output
● myproject.service - Gunicorn instance to serve myproject
   Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2018-07-13 14:28:39 UTC; 46s ago
 Main PID: 28232 (gunicorn)
    Tasks: 4 (limit: 1153)
   CGroup: /system.slice/myproject.service
           ├─28232 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007
           ├─28250 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007
           ├─28251 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007
           └─28252 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007

 Configure Nginx

Create a Nginx site configuration file

sudo nano /etc/nginx/sites-available/myproject

The content of the file is:

server {
    listen 80;
    server_name your_domain www.your_domain;

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/sammy/myproject/myproject.sock;
    }
}

Special attention: your_domain should be replaced with your actual domain name, and this part of sammy/myprojecct/project should also be modified to yours

For my understanding, sammy/project refers to the working directory WorkingDirectory, and myproject.sock refers to the Unix socket file unix:myproject.sock, which corresponds to the content in /etc/systemd/system/myproject.service.

Enable Nginx site configuration block (server block configuration):

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

After enabling, you can test the configuration of nginx:

sudo nginx -t

If there is an error, you can check the syntax of the above configuration block file, etc., and also check that there are files other than default in the /etc/nginx/sites-enabled directory, and delete unnecessary files. Because every file is added to the configuration.

If there are no errors, you can restart nginx:

sudo systemctl restart nginx

Because we no longer need the firewall port number 5000, we can modify the firewall as follows:

sudo ufw delete allow 5000
sudo ufw allow 'Nginx Full'

Enter your domain name in the browser address:

http://your_domain

You should see:

If there is any error, you can check:

  • sudo less /var/log/nginx/error.log: Check the Nginx error log.
  • sudo less /var/log/nginx/access.log: Check the Nginx access log.
  • sudo journalctl -u nginx: Check the Nginx process log.
  • sudo journalctl -u myproject: Check the Gunicorn log of the Flask application.

That's it for the introduction. Application security is also introduced in the original text. I didn't understand it. You can read the original text if necessary.

Guess you like

Origin blog.csdn.net/leon_zeng0/article/details/108837619