Disclaimer: This post is not a tutorial on how to create a Flask app, but rather how to deploy it using Gunicorn and Nginx. If you’re new to these concepts or need a refresher, consider brushing up on the basics before diving into this article.

One task in working as a research assistant in Professor Chen Li’s QueryBooster was migrating the backend code from SimpleHttpServer to Flask and deploying our website using Gunicorn, and Nginx. In this post, I hope to explain how to deploy a Flask application with Gunicorn and Nginx.

As an example, I will be demonstrating the deployment with the project that I worked on (QueryBooster). However, you should be able to follow this guide by using your own Flask project.

Deployment Guide

This guide will walk you through deploying QueryBooster on your server. Follow the steps below to set up and run QueryBooster.

Running Flask with Gunicorn

Clone the project

Enter server and clone the project

1
2
ssh username@hostname
git clone https://github.com/ISG-ICS/QueryBooster.git

Requirements

Navigate to the QueryBooster directory and set up a Python virtual environment, activate it, and install the required packages.

1
2
3
4
cd QueryBooster
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Compile and Deploy QueryBooster Client

To compile and deploy the QueryBooster client, go to the client directory and run the following commands:

1
2
3
cd client/
npm i
npm run build

Run QueryBooster server locally

Now, navigate to the server directory and start the QueryBooster server using Gunicorn:

1
2
cd ../server
gunicorn -w 4 -b 0.0.0.0:8000 'wsgi:app'

You can access QueryBooster locally at http://ip:8000.

Opening Firewall

To enable HTTP and HTTPS traffic, make sure ports 80 and 443 are accessible by modifying your firewall rules. For CentOS, use the following commands:

1
2
3
4
sudo firewall-cmd --zone=public --add-port=80/tcp --permanent
sudo firewall-cmd --zone=public --add-port=443/tcp --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --list-all

Implementing querybooster.service controlled by systemctl as system process

To ensure that QueryBooster starts automatically after server reboots or crashes, create a systemd service unit file.

1
sudo vi /etc/systemd/system/querybooster.service

Add the following content to the querybooster.service file:

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
Description=Gunicorn instance to serve Flask app
After=network.target

[Service]
User=waans11
Group=waans11
WorkingDirectory=/home/waans11/QueryBooster/server
Environment="PATH=/home/waans11/QueryBooster/venv/bin"
ExecStart=/bin/bash -c 'source /home/waans11/QueryBooster/venv/bin/activate; gunicorn -w 4 --bind 127.0.0.1:8000 wsgi:app'

[Install]
WantedBy=multi-user.target

Reload the systemd manager configuration and start the QueryBooster service:

1
2
3
4
systemctl daemon-reload
sudo systemctl start querybooster
sudo systemctl enable querybooster
sudo systemctl status querybooster

The sudo systemctl enable querybooster command ensures that QueryBooster starts automatically on system boot.

The command sudo systemctl status querybooster will show if querybooster is active:

img

Enable HTTPS

Generate Key and CSR Files

Generate a key file (server.key) and a Certificate Signing Request (CSR) file (server.csr). Make sure to set a password for the key file.

*** Note: we will be needing the password when we set up Nginx so do NOT forget the password***

  • Generate key file:
1
openssl genrsa -des3 -out server.key 2048
  • Generate CSR file:
1
openssl req -new -key server.key -out server.csr

2. Get a signed certificate from a CA (Certificate Authority).

Get a signed certificate from a CA (Certificate Authority) of your choice. There are many that are free.

Note 1: So far there are three files: server.key, server.csr, server.crt. Please note for the difference. You only need server.csr to obtain server.crt, and no longer needed it for following steps. For all following steps, you should be using server.crt

Note 2: if the files are located under /etc/nginx/ssl/ there might be problems with File access: permission denied due to system security policy.

Setting up Nginx

Install Nginx based on your OS. For CentOS, use the following commands:

1
2
3
sudo yum install epel-release
sudo yum update
sudo yum install nginx

for more information: https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/

Create password file for server.key

If you have created a password for server.key. You need to create a file named querybooster.pass inside /etc/ssl/certs/ so that nginx can access the server.py file.

Use the command below and write down the password:

1
sudo vi /etc/ssl/certs/querybooster.pass

Setting up Nginx configurations

The files we modify inside nginx are /etc/nginx/nginx.conf and /etc/nginx/conf.d/query_booster.conf

Modify nginx.conf to the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
worker_connections 1024;
}

http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096;

include /etc/nginx/mime.types;
default_type application/octet-stream;

# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*;

}

Create file query_booster.conf:

1
sudo vi /etc/nginx/conf.d/query_booster.conf

Add the following content to the query_booster.conf file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 80;
listen 443 ssl;
server_name querybooster.ics.uci.edu;

ssl_certificate /etc/ssl/certs/querybooster_ics_uci_edu.pem;
ssl_certificate_key /etc/ssl/certs/server.key;
ssl_password_file /etc/ssl/certs/querybooster.pass;

location / {
proxy_pass http://127.0.0.1:8000/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Prefix /;
}
}

Test Nginx

Test the Nginx configuration file for syntax errors:

1
sudo nginx -t

The output should look similar to this:

img

Otherwise, check nginx.conf and query_booster.conf for syntax errors.

Reload and start Nginx

1
2
sudo nginx -s reload
sudo systemctl start nginx # or sudo systemctl restart nginx

Now, you can access QueryBooster through the domain querybooster.ics.uci.edu from the web server.

For a more detailed guide, please check the wiki in QueryBooster