gunicorn

Need to read about gunicorn because I use it to deploy my Flask application on the server.

Date Created:

References



Definitions


  • WSGI
    • WSGI is the Web Server Gateway Interface. It is a specification that describes how a web server communicates with web applications, and how web applications can be chained together to process one request.


Notes


Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for Unix. It's a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.

Features:

  • Natively supports WSGI, Django, and Paster
  • Automatic worker process management
  • Simple Python configuration
  • Multiple worker configurations
  • Various server hooks for extensibility
  • Compatible with Python 3.x >= 3.7


Installation


Requirements: Python 3.x >= 3.7

To install the latest version of Gunicorn:

$ pip install gunicorn 

You may want to install Eventlet and Gevent if you expect your application code may need to pause for extended periods of time during request processing. See the design docs for more information.

$ pip install greenlet            # Required for both
$ pip install eventlet # For eventlet workers
$ pip install gunicorn[eventlet] # Or, using extra
$ pip install gevent # For gevent workers
$ pip install gunicorn[gevent] # Or, using extra

If you are using Debian GNU/Linux it is recommended that you use system packages to install Gunicorn - i.e., dnf apt-get install gunicorn. This has a number of advantages:

  • Zero-effort installation
  • Sensible default locations for logs (/var/log/gunicorn)
  • Improved security
  • Sensible upgrade path


Running Gunicorn


Basic usage:

$ gunicorn [OPTIONS] [WSGI_APP]

Where WSGI_APP is of the pattern $(MODULE_NAME):(VARIABLE_NAME)$. The module name can be a full dotted path. The variable name refers to a WSGI callable that should be found in the specified module.

The variable name can be a variable (like the app variable in a simple Flask application) or a function call - like when you are following the application factory pattern.

Commonly Used Arguments

  • -c CONFIG, --config=CONFIG
    • Specify a config file in the form $(PATH)
  • -b BIND, --bind=BIND
    • Specify a server socket to bind in the form of $(HOST)
  • -w WORKERS, --workers=WORKERS
    • The number of worker processes. Should generally be 2-4.
  • -k WORKERCLASS, --worker-class=WORKERCLASS
    • The type of worker process to run
  • -n APP_NAME, --name=APP_NAME


Configuration


  • Gunicorn first reads environment variables for configuration settings
    • Configuration settings in the command line override all other configuration settings
  • Gunicorn then reads configuration from a framework specific configuration file
    • Currently, only paster applications have access to framework specific settings.
  • The third source of configuration information is an optional configuration file gunicorn.conf.py searched in the current working directory or specified using a command line argument.
    • The configuration file should be a valid Python source file with a python extension (e.g. gunicorn.conf.py)
  • The forth place of configuration information are command line arguments stored in an environment variable named GUNICORN_CMD_ARGS

To print the resolved configuration:

$ gunicorn --print-config APP_MODULE


Settings



Deploying Gunicorn


It is strongly recommended to use Nginx.

worker_processes 1;

user nobody nogroup;
# 'user nobody nobody;' for systems with 'nobody' as a group instead
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
worker_connections 1024; # increase if you have lots of clients
accept_mutex off; # set to 'on' if nginx worker_processes > 1
# 'use epoll;' to enable for Linux 2.6+
# 'use kqueue;' to enable for FreeBSD, OSX
}

http {
include mime.types;
# fallback in case we can't determine a type
default_type application/octet-stream;
access_log /var/log/nginx/access.log combined;
sendfile on;

upstream app_server {
# fail_timeout=0 means we always retry an upstream even if it failed
# to return a good HTTP response

# for UNIX domain socket setups
server unix:/tmp/gunicorn.sock fail_timeout=0;

# for a TCP configuration
# server 192.168.0.7:8000 fail_timeout=0;
}

server {
# if no Host match, close the connection to prevent host spoofing
listen 80 default_server;
return 444;
}

server {
# use 'listen 80 deferred;' for Linux
# use 'listen 80 accept_filter=httpready;' for FreeBSD
listen 80;
client_max_body_size 4G;

# set the correct host(s) for your site
server_name example.com www.example.com;

keepalive_timeout 5;

# path for static files
root /path/to/app/current/public;

location / {
# checks for static file, if not found proxy to app
try_files $uri @proxy_to_app;
}

location @proxy_to_app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
proxy_pass http://app_server;
}

error_page 500 502 503 504 /500.html;
location = /500.html {
root /path/to/app/current/public;
}
}
}

It is recommended to pass protocol information to Gunicorn. Many web frameworks use this information to generate URLs. To configuration Nginx to pass an appropriate header, add a proxy_set_header directive to your location block:

...
proxy_set_header X-Forwarded-Proto $scheme;
...

Using Virtualenv

To serve an app from a Virtualenv it is generally easiest to just install Gunicorn directly into the Virtualenv. This will create a set of Gunicorn scripts for that Virtualenv which can be used to run applications normally.


Gunicorn and Flask


Gunicorn is easy to install, as it does not require external dependencies or compilation. It runs on Windows only under WSL.

Gunicorn should not be run as root because it would cause your application code to run as root, which is not secure. However, this means it will not be possible to bind port 80 or 443. Instead, a reverse proxy such as nginx should be used in front of Gunicorn.

When deploying Gunicorn and a Flask application behind a proxy, you need to tell Flask it is behind a Proxy. From the WSGI server and Flask application's perspectives, requests are now coming from the HTTP server to the local address, rather than from the remote address to the external server address. HTTP servers should set the X-Forwarded- headers to pass on the real values to the application. The application can then be told to trust and use those values by wrapping it with the X-Forwarded-For Proxy Fix middleware provided by Werkzeug.

This middleware should only be used if the application is actually behind a proxy, and should be configured with the number of proxies that are chained in front of it.

from werkzeug.middleware.proxy_fix import ProxyFix

app.wsgi_app = ProxyFix(
app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
)

Insert Math Markup

ESC
About Inserting Math Content
Display Style:

Embed News Content

ESC
About Embedding News Content

Embed Youtube Video

ESC
Embedding Youtube Videos

Embed TikTok Video

ESC
Embedding TikTok Videos

Embed X Post

ESC
Embedding X Posts

Embed Instagram Post

ESC
Embedding Instagram Posts

Insert Details Element

ESC

Example Output:

Summary Title
You will be able to insert content here after confirming the title of the <details> element.

Insert Table

ESC
Customization
Align:
Preview:

Insert Horizontal Rule

#000000

Preview:


Insert Chart

ESC

View Content At Different Sizes

ESC

Edit Style of Block Nodes

ESC

Edit the background color, default text color, margin, padding, and border of block nodes. Editable block nodes include paragraphs, headers, and lists.

#ffffff
#000000

Edit Selected Cells

Change the background color, vertical align, and borders of the cells in the current selection.

#ffffff
Vertical Align:
Border
#000000
Border Style:

Edit Table

ESC
Customization:
Align:

Upload Lexical State

ESC

Upload a .lexical file. If the file type matches the type of the current editor, then a preview will be shown below the file input.

Upload 3D Object

ESC

Upload Jupyter Notebook

ESC

Upload a Jupyter notebook and embed the resulting HTML in the text editor.

Insert Custom HTML

ESC

Edit Image Background Color

ESC
#ffffff

Insert Columns Layout

ESC
Column Type:

Select Code Language

ESC
Select Coding Language