Introduction
This guide will help you to setup a Flask app using gunicorn and nginx. It will cover also how to do a load balance with many instances. You need to be familiar with virtualenv and some minimal python.
Step 1: Install requirements
Install nginx and python dependencies
sudo apt update
sudo apt install python-pip python-dev nginx
Step 2: Install python dependencies
Prepare the virtualenv. In this guide we will use virtualenv wrapper. If you want to know more about virtualenv wrapper installation check here.
sudo pip install pip -U # update pip
sudo pip install virtualenvwrapper
# next command are for using virtualenvwrapper with bash
export WORKON_HOME=$HOME/.virtualenvs
export PROJECT_HOME=$HOME/Devel
source /usr/local/bin/virtualenvwrapper.sh
mkvirtualenv flask_app
All your virtualenv will be saved at your home directory under the name .virtualenv. Now it's time to isntall your flask app deps:
workon flask_app
pip install -r requirements.txt # or python setup.py install
You are done with dep installation, continue to step 3.
Step 3: Congirue gunicorn to work with flask
Install gunicorn with:
pip install gunicorn
Create a wsgi module like this one:
from myproject import application
if __name__ == "__main__":
application.run()
Start gunicorn with:
gunicorn --bind 0.0.0.0:8000 wsgi
Test with your browser at your ip address and port 8000 or localhost http://127.0.0.1:8000 If everything if working, you can configure gunicorn to start at boot with step 4.
Step 4: Configure gunicorn at boot
We are going to use systemd to start the app at boot. Add a new file at /etc/systemd/system/ with .serice extension and with this content: If you every need to debug systemd, remeber to use journalctl command (example sudo journalctl -u flask_app.service)
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
PIDFile=/home/application_user/app.pid
User=someuser
Group=someuser
RuntimeDirectory=gunicorn
WorkingDirectory=/home/application_user/flask_app
ExecStart=/home/application_user/.virtualenvs/flask_app/bin/gunicorn --pid /home/application_user/app.pid --workers=8 \
--bind unix:/home/application_user/app.socket applicationname.wsgi
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Remeber to modify the settings according to your setup. We used 8 workers since we had a 8 core cpu.
Add the .socket file at /etc/systemd/system/gunicorn.socket with:
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn/socket
[Install]
WantedBy=sockets.target
And finnaly add the file /etc/tmpfiles.d/gunicorn.conf with:
d /run/gunicorn 0755 someuser somegroup -
Enable the service with:
systemctl enable gunicorn.socket
Finnaly start the service with:
systemctl start gunicorn.socket
Step 5: Configure nginx with gunicorn
Add a new file to /etc/nginx/sites-available with this content:
server {
listen 80;
server_name server_domain_or_IP;
location / {
include proxy_params;
proxy_pass unix:/home/application_user/app.socket;
}
}
Enable the site with:
sudo ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enables/flask_app
sudo service nginx restart
Step 6: Load balance with multiple hosts usign nginx
We will use 3 computers with the backend running using gunicorn. Each will use 8 workers. This time it will bind to port 8000.
The ExecStart we used was the following:
ExecStart=/home/application_user/.virtualenvs/flask_app/bin/gunicorn --pid /home/application_user/app.pid --workers=8\
--bind 0.0.0.0:8000 applicationname.wsgi
Then we created an upstream on nginx using this settings:
http {
upstream app_cluster {
server 192.168.0.2:8000;
server 192.168.0.3:8000;
server 192.168.0.4:8000;
}
server {
listen 80;
location / {
proxy_pass http://app_cluster;
}
}
}