A simple web server might only serve static files. The client makes an HTTP request to a URL handled by the server, say
and the website maps the path of the URL, todo/list.html, to a file on the file system, say
The file is then read by the server and the contents of the file are returned to the client as the body of the HTTP response.
An early way to create a dynamic web server was to use the CGI protocol. The client makes an HTTP request to a URL handled by the server, say
and the website maps the path of the URL to an executable on the file system, say
The executable is called the CGI script though in general it could be an executable binary.
The server runs the CGI script and returns its standard output to the client as the body of the response. In the case of a POST request, the CGI script reads the form data via standard input. The server sets environment variables to communicate metadata about the request to the CGI script. Two of the most important are:
For example, the CGI script might inspect REQUEST_METHOD to see if the request is a GET request, and if so it might parse the URL in REQUEST_URI to get URL parameters.
The CGI protocol requires launching a new process for each HTTP request. Faster methods for handling dynamic HTTP requests have been developed.
The uwsgi protocol, which is distinct from the uWSGI server described below, is one such replacement method. The web server communicates via a binary protocol over TCP with a uwsgi server. The uwsgi server acts like the CGI script and generates the content to be returned to the client as the body of the HTTP request.
Nginx is a webserver which can serve static content and knows the uwsgi protocol.
When I ran the following on my Ubuntu server
$ sudo apt-get install nginx
an executable was installed at /usr/sbin/nginx. It looks like nginx is installed as a service and will already be running when the installation finished. The service can be stopped or started with:
$ systemctl nginx start|stop
Show how to...
- run another nginx server
- set the port
- serve static content
- talk to a uwsgi server
When you run
$ pip install uwsgi
a command line executable called uwsgi is installed on your system. If I run
$ uwsgi --help
it lists over 900 command line options. Here are some of the more useful options:
Usage: /Users/clark/ve/bin/uwsgi [options...] -s|--socket bind to the specified UNIX/TCP socket using default protocol -s|--uwsgi-socket bind to the specified UNIX/TCP socket using uwsgi protocol --http-socket bind to the specified UNIX/TCP socket using HTTP protocol --http add an http router/server on the specified address --httprouter add an http router/server on the specified address -p|--processes spawn the specified number of workers/processes -p|--workers spawn the specified number of workers/processes --threads run each worker in prethreaded mode with the specified number of threads -M|--master enable master process --wsgi-file load .wsgi file -w|--module load a WSGI module -w|--wsgi load a WSGI module --file load .wsgi file --stats enable the stats server on the specified address --stats-server enable the stats server on the specified address --chdir chdir to specified directory before apps loading --pythonpath add directory (or glob) to pythonpath --python-path add directory (or glob) to pythonpath --pp add directory (or glob) to pythonpath --env set environment variable --callable set default WSGI callable name -R|--max-requests reload workers after the specified amount of managed requests -t|--harakiri set harakiri timeout --logger set/append a logger --vacuum try to remove all of the generated file/sockets --post-buffering set size in bytes after which will buffer to disk instead of memory --post-buffering-bufsize set buffer size for read() in post buffering mode
One can use a uwsgi.ini file instead of command line arguments. Thus, instead of running uswgi this way:
$ uwsgi --wsgi-file application.py --http-socket 0.0.0.0:9190 --master --processes 2
You could run it this way:
$ cat uwsgi.ini [uwsgi] http-socket = 0.0.0.0:9190 processes = 2 master = true wsgi-file = application.py $ usgi uwsgi.ini
The uWSGI server is implemented in C, but it designed for running application code in other languages, such as Python. uWSGI must be recompiled to change the application languages which are supported.
If Python is supported, the application developer implements a Python function called application. When uWSGI is run, the --wsgi-file --flag is used to specify the file containing the application function:
$ cat hello.py def application(env, start_response): start_response('200 OK', [('Content-Type','text/html')]) return [b"Hello World"] $ ./ve/bin/uwsgi --http 127.0.0.1:9090 --wsgi-file hello.py
The example uses the --http --flag to run the uWSGI server as a stand-alone web server without another web server in front of it.
The example also shows how the uWSGI server interfaces with the Python code. It passes two arguments to the application function, the second of which is a callback function which the Python code uses to specify the status code and the response headers. The body of the response is an array of byte strings. The env is a dictionary: https://www.python.org/dev/peps/pep-0333/#environ-variables
uWSGI runs with an optional master process and 1 or more worker processes. The worker processes listen on a common socket with the SO_REUSEADDR flag so each request is assigned to one of them by the operating system.
The master process is optional, but is usually used in production. You can read the code to get an idea of what services it provides: https://github.com/unbit/uwsgi/blob/master/core/master.c
Flask is a Python package for implementing web application. A Flask application can act as a uWSGI application.
When setting up a Flask application, one imports the Flask class and instantiates an object. This object presumably has a call method which allows it to be called as the application function describes above.
Thus, to use Flask with uWSGI, one just needs to put something like this in the --wsgi-file--:
import flask application = Flask(__name__, template_folder='layout')
However, it is customary to put the Flask object in a variable named app since it makes declaring routes less verbose. One could assign the Flask object to both app and application, or one could use the uWSGI --callable --option to change the name of the variable containing the uWSGI application.