Moving to production with Nginx, uWsgi, Systemd, Flask, Ubuntu (18.04)

In this article, we will see how to move our code base to a production environment. Following are the step by step guide to do it.

1.) Update your Ubuntu system

sudo apt update

2.) Install basic python3, pip and essentials on the machine

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

3.) We need to create a virtual environment separate for our flask app so that it is isolated from rest of the python packages and dependencies don’t get overlap

sudo apt install python3-venv

4.) Let us consider our folder structure in the following way:

chatBotMaster (/home/ubuntu/chatBotMaster)
|
|
— — — chatBotEnv (virtual environment for chatbot)
|
|
— — — ChatBotAPI-HUBOT-Latest (Flask App 1)
|
|
— — — — ChatBotAppMain.py
|
— — — — wsgi.py
|
— — — — hubot.ini
|
|
— — — Danone_App_V8 (Flask App 2)
|
|
— — — — main.py
|
— — — — wsgi.py
|
— — — — Danone_App_V8.ini

5.) Create the main folder and inside which create a virtual environment (In this article we have assumed a single environment for all the flask apps)

mkdir chatBotMaster
cd !$
python3 -m venv chatBotEnv
source chatBotEnv/bin/activate

Now your terminal will appear in this way

(chatBotEnv) ubuntu@ip-172–31–24–92:

6.) Install flask and uwsgi on your newly created enviroment

pip install wheel uwsgi flask

7.) Create your flask app (You should know this if you are moving to production!!)

8.) Create a wsgi entry point for your application — wsgi.py (It will be in the same folder as your main.py)

Code: (/home/chatBotMaster/Danone_App_V8/wsgi.py)
from myproject import app
if __name__ == “__main__”:
app.run()

9.) Test if your uwsgi is working or not

 uwsgi — socket 0.0.0.0:5000 — protocol=http -w wsgi:app

You can test this my opening other terminal and typing command: curl http://0.0.0.0:5000 — This will return you the output of the URL

Now close the wsgi server

10.) Now you will create the configuration file for the uwsgi server — Danone_App_V8.ini (It will be in the same folder as your main.py)

Config: (/home/chatBotMaster/Danone_App_V8/Danone_App_V8.ini)
[uwsgi]
module = wsgi:app
app = Danone_App_V8
master = true
processes = 5
socket = Danone_App_V8.sock
chmod-socket = 660
vacuum = true
die-on-term = true
manage-script-name = true
mount = /danone_v8/=/home/ubuntu/chatBotMaster/Danone_App_V8/main.py
callable = app

11.) Now let’s create a systemd file for the uwsgi. It will be responsible to run the wsgi server whenever server boots.

sudo nano /etc/systemd/system/Danone_App_V8.service
Code:
[Unit]
Description=uWSGI instance to serve Danone_App_V8After=network.target
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/chatBotMaster/Danone_App_V8
Environment=”PATH=/home/ubuntu/chatBotMaster/chatBotEnv/bin”
ExecStart=/home/ubuntu/chatBotMaster/chatBotEnv/bin/uwsgi — ini Danone_App_V8.ini
[Install]
WantedBy=multi-user.target

12.) We can now start the uWSGI service we created and enable it so that it starts at boot:

sudo systemctl start myproject
sudo systemctl enable myproject
**Important: The .sock file automatically created. If you want to change some url or anything else just delete the .sock file from the location and run the following command to recreate the .sock file
sudo systemctl restart myproject

13.) You can check the status of the systemd file with help of the following command:

sudo systemctl status myproject

14.) Now let us configure the nginx for our requests and it passes the request to the uWsgi server. (myproject is just the basic name it will serve for all your flask apps)

sudo nano /etc/nginx/sites-available/myproject
Code:
server {
    listen 80;
server_name {public_ip};

location /danone_v8/ {
include uwsgi_params;
uwsgi_pass unix:/home/ubuntu/chatBotMaster/Danone_App_V8/Danone_App_V8.sock;
     }
     location /hubot/ {
         include uwsgi_params;
uwsgi_pass unix:/home/ubuntu/chatBotMaster/ChatBotAPI-HUBOT- Latest/hubot.sock;
    }
}
*Note: As you can see in the above configuration, we have two different flask app which are seprated which the help of the link /danone_v8/ and /hubot/. The reference of these links is given in the .ini configuration file which we can create in the previous section.

mount and callable in the .ini file are separating the link of the URL so that they know which folder we are referencing to.

15.) create the link to the site-enabled folder

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

16.) Finishing up commands:

sudo nginx -t
sudo systemctl restart nginx
sudo ufw delete allow 5000
sudo ufw allow ‘Nginx Full’

You can check for errors/access of the Nginx server on log files which are created in the following location:

var/log/nginx/error.log
var/log/nginx/access.log

17.) You can access the URLs of the flask apps in the following way:

http://{public ip}/danone_v8/rest_of_the_url — (flaskapp1)
http://{public ip}/hubot/rest_of_the_url — (flaskapp2)

Thanks.
Please share your views in the comments.