Standalone WSGI Servers
Most WSGI servers also provide HTTP servers, so they can run a WSGI application and make it available externally.
It may still be a good idea to run the server behind a dedicated HTTP server such as Apache or Nginx. See Proxy Setups if you run into issues with that.
Gunicorn
Gunicorn is a WSGI and HTTP server for UNIX. To run a Flask application, tell Gunicorn how to import your Flask app object.
$ gunicorn -w 4 -b 0.0.0.0:5000 your_project:app
The -w 4
option uses 4 workers to handle 4 requests at once. The -b 0.0.0.0:5000
serves the application on all interfaces on port 5000.
Gunicorn provides many options for configuring the server, either through a configuration file or with command line options. Use gunicorn --help
or see the docs for more information.
The command expects the name of your module or package to import and the application instance within the module. If you use the application factory pattern, you can pass a call to that.
$ gunicorn -w 4 -b 0.0.0.0:5000 "myproject:create_app()"
Async with Gevent or Eventlet
The default sync worker is appropriate for many use cases. If you need asynchronous support, Gunicorn provides workers using either gevent or eventlet. This is not the same as Python’s async/await
, or the ASGI server spec.
When using either gevent or eventlet, greenlet>=1.0 is required, otherwise context locals such as request
will not work as expected. When using PyPy, PyPy>=7.3.7 is required.
To use gevent:
$ gunicorn -k gevent -b 0.0.0.0:5000 your_project:app
To use eventlet:
$ gunicorn -k eventlet -b 0.0.0.0:5000 your_project:app
uWSGI
uWSGI is a fast application server written in C. It is very configurable, which makes it more complicated to setup than Gunicorn. It also provides many other utilities for writing robust web applications. To run a Flask application, tell Gunicorn how to import your Flask app object.
$ uwsgi --master -p 4 --http 0.0.0.0:5000 -w your_project:app
The -p 4
option uses 4 workers to handle 4 requests at once. The --http 0.0.0.0:5000
serves the application on all interfaces on port 5000.
uWSGI has optimized integration with Nginx and Apache instead of using a standard HTTP proxy. See configuring uWSGI and Nginx.
Async with Gevent
The default sync worker is appropriate for many use cases. If you need asynchronous support, uWSGI provides workers using gevent. It also supports other async modes, see the docs for more information. This is not the same as Python’s async/await
, or the ASGI server spec.
When using gevent, greenlet>=1.0 is required, otherwise context locals such as request
will not work as expected. When using PyPy, PyPy>=7.3.7 is required.
$ uwsgi --master --gevent 100 --http 0.0.0.0:5000 -w your_project:app
Gevent
Prefer using Gunicorn with Gevent workers rather than using Gevent directly. Gunicorn provides a much more configurable and production-tested server. See the section on Gunicorn above.
Gevent allows writing asynchronous, coroutine-based code that looks like standard synchronous Python. It uses greenlet to enable task switching without writing async/await
or using asyncio
.
It provides a WSGI server that can handle many connections at once instead of one per worker process.
Eventlet, described below, is another library that does the same thing. Certain dependencies you have, or other consideration, may affect which of the two you choose to use
To use gevent to serve your application, import its WSGIServer
and use it to run your app
.
from gevent.pywsgi import WSGIServer from your_project import app http_server = WSGIServer(("", 5000), app) http_server.serve_forever()
Eventlet
Prefer using Gunicorn with Eventlet workers rather than using Eventlet directly. Gunicorn provides a much more configurable and production-tested server. See the section on Gunicorn above.
Eventlet allows writing asynchronous, coroutine-based code that looks like standard synchronous Python. It uses greenlet to enable task switching without writing async/await
or using asyncio
.
It provides a WSGI server that can handle many connections at once instead of one per worker process.
Gevent, described above, is another library that does the same thing. Certain dependencies you have, or other consideration, may affect which of the two you choose to use
To use eventlet to serve your application, import its wsgi.server
and use it to run your app
.
import eventlet from eventlet import wsgi from your_project import app wsgi.server(eventlet.listen(("", 5000), app)
Twisted Web
Twisted Web is the web server shipped with Twisted, a mature, non-blocking event-driven networking library. Twisted Web comes with a standard WSGI container which can be controlled from the command line using the twistd
utility:
$ twistd web --wsgi myproject.app
This example will run a Flask application called app
from a module named myproject
.
Twisted Web supports many flags and options, and the twistd
utility does as well; see twistd -h
and twistd web -h
for more information. For example, to run a Twisted Web server in the foreground, on port 8080, with an application from myproject
:
$ twistd -n web --port tcp:8080 --wsgi myproject.app
Proxy Setups
If you deploy your application using one of these servers behind an HTTP proxy you will need to rewrite a few headers in order for the application to work. The two problematic values in the WSGI environment usually are REMOTE_ADDR
and HTTP_HOST
. You can configure your httpd to pass these headers, or you can fix them in middleware. Werkzeug ships a fixer that will solve some common setups, but you might want to write your own WSGI middleware for specific setups.
Here’s a simple nginx configuration which proxies to an application served on localhost at port 8000, setting appropriate headers:
server { listen 80; server_name _; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; location / { proxy_pass http://127.0.0.1:8000/; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
If your httpd is not providing these headers, the most common setup invokes the host being set from X-Forwarded-Host
and the remote address from X-Forwarded-For
:
from werkzeug.middleware.proxy_fix import ProxyFix app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)
Trusting Headers
Please keep in mind that it is a security issue to use such a middleware in a non-proxy setup because it will blindly trust the incoming headers which might be forged by malicious clients.
If you want to rewrite the headers from another header, you might want to use a fixer like this:
class CustomProxyFix(object): def __init__(self, app): self.app = app def __call__(self, environ, start_response): host = environ.get('HTTP_X_FHOST', '') if host: environ['HTTP_HOST'] = host return self.app(environ, start_response) app.wsgi_app = CustomProxyFix(app.wsgi_app)
© 2007–2022 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.1.x/deploying/wsgi-standalone/