1Standalone WSGI Containers
2==========================
3
4There are popular servers written in Python that contain WSGI applications and
5serve HTTP.  These servers stand alone when they run; you can proxy to them
6from your web server.  Note the section on :ref:`deploying-proxy-setups` if you
7run into issues.
8
9Gunicorn
10--------
11
12`Gunicorn`_ 'Green Unicorn' is a WSGI HTTP Server for UNIX. It's a pre-fork
13worker model ported from Ruby's Unicorn project. It supports both `eventlet`_
14and `greenlet`_. Running a Flask application on this server is quite simple::
15
16    $ gunicorn myproject:app
17
18`Gunicorn`_ provides many command-line options -- see ``gunicorn -h``.
19For example, to run a Flask application with 4 worker processes (``-w
204``) binding to localhost port 4000 (``-b 127.0.0.1:4000``)::
21
22    $ gunicorn -w 4 -b 127.0.0.1:4000 myproject:app
23
24The ``gunicorn`` command expects the names of your application module or
25package and the application instance within the module. If you use the
26application factory pattern, you can pass a call to that::
27
28    $ gunicorn "myproject:create_app()"
29
30.. _Gunicorn: https://gunicorn.org/
31.. _eventlet: https://eventlet.net/
32
33
34uWSGI
35--------
36
37`uWSGI`_ is a fast application server written in C. It is very configurable
38which makes it more complicated to setup than gunicorn.
39
40Running `uWSGI HTTP Router`_::
41
42    $ uwsgi --http 127.0.0.1:5000 --module myproject:app
43
44For a more optimized setup, see :doc:`configuring uWSGI and NGINX <uwsgi>`.
45
46.. _uWSGI: https://uwsgi-docs.readthedocs.io/en/latest/
47.. _uWSGI HTTP Router: https://uwsgi-docs.readthedocs.io/en/latest/HTTP.html#the-uwsgi-http-https-router
48
49Gevent
50-------
51
52`Gevent`_ is a coroutine-based Python networking library that uses
53`greenlet`_ to provide a high-level synchronous API on top of `libev`_
54event loop::
55
56    from gevent.pywsgi import WSGIServer
57    from yourapplication import app
58
59    http_server = WSGIServer(('', 5000), app)
60    http_server.serve_forever()
61
62.. _Gevent: http://www.gevent.org/
63.. _greenlet: https://greenlet.readthedocs.io/en/latest/
64.. _libev: http://software.schmorp.de/pkg/libev.html
65
66Twisted Web
67-----------
68
69`Twisted Web`_ is the web server shipped with `Twisted`_, a mature,
70non-blocking event-driven networking library. Twisted Web comes with a
71standard WSGI container which can be controlled from the command line using
72the ``twistd`` utility::
73
74    $ twistd web --wsgi myproject.app
75
76This example will run a Flask application called ``app`` from a module named
77``myproject``.
78
79Twisted Web supports many flags and options, and the ``twistd`` utility does
80as well; see ``twistd -h`` and ``twistd web -h`` for more information. For
81example, to run a Twisted Web server in the foreground, on port 8080, with an
82application from ``myproject``::
83
84    $ twistd -n web --port tcp:8080 --wsgi myproject.app
85
86.. _Twisted: https://twistedmatrix.com/trac/
87.. _Twisted Web: https://twistedmatrix.com/trac/wiki/TwistedWeb
88
89.. _deploying-proxy-setups:
90
91Proxy Setups
92------------
93
94If you deploy your application using one of these servers behind an HTTP proxy
95you will need to rewrite a few headers in order for the application to work.
96The two problematic values in the WSGI environment usually are ``REMOTE_ADDR``
97and ``HTTP_HOST``.  You can configure your httpd to pass these headers, or you
98can fix them in middleware.  Werkzeug ships a fixer that will solve some common
99setups, but you might want to write your own WSGI middleware for specific
100setups.
101
102Here's a simple nginx configuration which proxies to an application served on
103localhost at port 8000, setting appropriate headers:
104
105.. sourcecode:: nginx
106
107    server {
108        listen 80;
109
110        server_name _;
111
112        access_log  /var/log/nginx/access.log;
113        error_log  /var/log/nginx/error.log;
114
115        location / {
116            proxy_pass         http://127.0.0.1:8000/;
117            proxy_redirect     off;
118
119            proxy_set_header   Host                 $host;
120            proxy_set_header   X-Real-IP            $remote_addr;
121            proxy_set_header   X-Forwarded-For      $proxy_add_x_forwarded_for;
122            proxy_set_header   X-Forwarded-Proto    $scheme;
123        }
124    }
125
126If your httpd is not providing these headers, the most common setup invokes the
127host being set from ``X-Forwarded-Host`` and the remote address from
128``X-Forwarded-For``::
129
130    from werkzeug.middleware.proxy_fix import ProxyFix
131    app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)
132
133.. admonition:: Trusting Headers
134
135   Please keep in mind that it is a security issue to use such a middleware in
136   a non-proxy setup because it will blindly trust the incoming headers which
137   might be forged by malicious clients.
138
139If you want to rewrite the headers from another header, you might want to
140use a fixer like this::
141
142    class CustomProxyFix(object):
143
144        def __init__(self, app):
145            self.app = app
146
147        def __call__(self, environ, start_response):
148            host = environ.get('HTTP_X_FHOST', '')
149            if host:
150                environ['HTTP_HOST'] = host
151            return self.app(environ, start_response)
152
153    app.wsgi_app = CustomProxyFix(app.wsgi_app)
154