NGINX and uWSGI for Flask-Philo app deployment¶
0. Install the tools you will need:¶
Install uWSGI:
sudo pip install uwsgi
Install NGINX:
sudo apt-get install nginx
1. Create a flask app using flask-philo:¶
To quickly generate a new Flask-Philo project, navigate to the directory in which you want to create the project and run:
flask-philo-admin startproject my_project
2. Create the WSGI Entry Point¶
Next, you will need to create a file that will serve as the entry point for your application. This will tell your uWSGI server how to interact with the application.
For example, you can call the file manage_uwsgi.py:
import os
import sys
import argparse
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.append(os.path.join(BASE_DIR, '../'))
from flask_philo import init_app
os.environ.setdefault('FLASK_PHILO_SETTINGS_MODULE', "config.development")
app = init_app(__name__, BASE_DIR)
3. Create a uWSGI Configuration File¶
In order to create something robust for long-term usage. You will create a uWSGI configuration file with some options.
[uwsgi]
pythonpath = <you_code_dir>/src/
wsgi-file = <you_code_dir>/src/manage_uwsgi.py
enable-threads = true
reload-on-rss=200
cpu-affinity = 1
reload-mercy = 20
max-requests = 5000
py-autoreload = 1
processes = 8
threads = 4
buffer-size = 95535
master = true
socket=/tmp/my_project.sock
chmod-socket = 660
plugin=python3
callable=app
harakiri = 40
vacuum = true
die-on-term = true
uid = www-data
gid = www-data
Some important observations can be made here:
processes = 8refers to the number of worker processes that will serve actual requests;- Since you will be using NGINX to handle client connections that will pass requests to uWSGI and the components will operate on the same computer, you will use a Unix socket. Sockets will be a more secure and faster solution;
socket=/tmp/my_project.sockrefers to the permissions on the socket, it’s set this way to allow NGINX to access it;callable = appis the entry point into the application where the web server can call a functions with some parameters.
4. Configure NGNIX to proxy to uWSGI¶
Create the NGNIX config file in order to establish the connection between NGNIX web server to
uWSGI. This connection will be made via socket. You can call this file default:
server {
server_name <your_nginx_server_name>;
listen 80;
rewrite ^ https://$server_name$request_uri? permanent;
access_log off;
}
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
server_name <your_nginx_server_name>;
underscores_in_headers on;
keepalive_timeout 0;
keepalive_requests 1000;
client_max_body_size 20m;
client_body_buffer_size 128k;
server_tokens off;
sendfile on;
uwsgi_buffer_size 264k;
uwsgi_buffers 8 264k;
uwsgi_busy_buffers_size 264k;
uwsgi_connect_timeout 600s;
uwsgi_read_timeout 600s;
uwsgi_send_timeout 600s;
uwsgi_ignore_client_abort on;
uwsgi_intercept_errors on;
uwsgi_max_temp_file_size 1024m;
location / {
uwsgi_read_timeout 30s;
include uwsgi_params;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
send_timeout 30s;
uwsgi_pass unix:/tmp/my_project.sock;
proxy_http_version 1.1;
proxy_redirect off;
}
}
gzip_http_version 1.1;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
gzip_types application/javascript text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_buffers 16 8k;
gzip_disable "MSIE [1-6].(?!.*SV1)";
gzip_proxied expired no-cache no-store private auth;
You will need to create some config files to handle variables and make reference to them like this: <your_nginx_server_name>.
5. Using systemd service file to manage multiple applications:¶
systemd will be responsible to start, stop, and keep alive the processes needed. It also:
- Provides aggressive parallelization capabilities
- Uses socket and D-Bus activation for starting services
- Offers on-demand starting of daemons
- Implements transactional dependency-based service control logic
- Tracks processes using Linux cgroups
- Supports snapshotting and restoring
- Maintains mount and automount points
You will need to create a service file, for example my_project.service. This file will contain the following content:
[Unit]
Description=My Project
After=syslog.target
ConditionPathExists=<you_code_dir>/src/manage.py
[Service]
ExecReload=/bin/kill -HUP $MAINPID
ExecStart=/usr/bin/uwsgi --ini <you_code_dir>/uwsgi.ini
RuntimeDirectory=<you_code_dir>/
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
Alias=my_project.service
6. To manage systemd service:¶
If you want to start systemd service, Debian-like for example, you should:
- Place your
my_project.servicefile in/etc/systemd/system/folder - Run the following commands:
systemctl daemon-reload
systemctl start|stop|restart my_project
or
systemctl daemon-reload
systemctl start|stop|restart my_project.service
For example, to start the service:
systemctl daemon-reload
systemctl start my_project.service
Example: How to deploy using Heroku¶
1. Create a uwsgi.ini file with the following content:¶
[uwsgi]
http-socket = :$(PORT)
master = true
processes = 4
die-on-term = true
module = manage_uwsgi:app
memory-report = true
stats = :22222
exec-pre-app = /sbin/ifconfig eth0
2. Create a file called Procfile with the following content:¶
web: uwsgi --ini uwsgi.ini
3. Then run the following command on a terminal window inside your project dir:¶
git push heroku master
4. To know more about how to deploy on Heroku, go to:¶
http://uwsgi-docs.readthedocs.io/en/latest/tutorials/heroku_python.html
You can also configure Chef (https://www.chef.io/) to perform all the steps in an automated fashion.