File: README.md
Flask
Flask is a lightweight WSGI web application framework. It is designed
to make getting started quick and easy, with the ability to scale up to
complex applications. It began as a simple wrapper around Werkzeug
and Jinja, and has become one of the most popular Python web
application frameworks.
Flask offers suggestions, but doesn't enforce any dependencies or
project layout. It is up to the developer to choose the tools and
libraries they want to use. There are many extensions provided by the
community that make adding new functionality easy.
A Simple Example
# save this as app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"$ flask run
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)Donate
The Pallets organization develops and supports Flask and the libraries
it uses. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, please
donate today.
Contributing
See our detailed contributing documentation for many ways to
contribute, including reporting issues, requesting features, asking or answering
questions, and making PRs.
File: docs/deploying/apache-httpd.rst
Apache httpd
Apache httpd_ is a fast, production level HTTP server. When serving
your application with one of the WSGI servers listed in :doc:index, it
is often good or necessary to put a dedicated HTTP server in front of
it. This "reverse proxy" can handle incoming requests, TLS, and other
security and performance concerns better than the WSGI server.
httpd can be installed using your system package manager, or a pre-built
executable for Windows. Installing and running httpd itself is outside
the scope of this doc. This page outlines the basics of configuring
httpd to proxy your application. Be sure to read its documentation to
understand what features are available.
.. _Apache httpd: https://httpd.apache.org/
Domain Name
Acquiring and configuring a domain name is outside the scope of this
doc. In general, you will buy a domain name from a registrar, pay for
server space with a hosting provider, and then point your registrar
at the hosting provider's name servers.
To simulate this, you can also edit your hosts file, located at/etc/hosts on Linux. Add a line that associates a name with the
local IP.
Modern Linux systems may be configured to treat any domain name that
ends with .localhost like this without adding it to the hosts
file.
.. code-block:: python
:caption: /etc/hosts
127.0.0.1 hello.localhostConfiguration
The httpd configuration is located at /etc/httpd/conf/httpd.conf on
Linux. It may be different depending on your operating system. Check the
docs and look for httpd.conf.
Remove or comment out any existing DocumentRoot directive. Add the
config lines below. We'll assume the WSGI server is listening locally athttp://127.0.0.1:8000.
.. code-block:: apache
:caption: /etc/httpd/conf/httpd.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
ProxyPass / http://127.0.0.1:8000/
RequestHeader set X-Forwarded-Proto http
RequestHeader set X-Forwarded-Prefix /The LoadModule lines might already exist. If so, make sure they are
uncommented instead of adding them manually.
Then :doc:proxy_fix so that your application uses the X-Forwarded
headers. X-Forwarded-For and X-Forwarded-Host are automatically
set by ProxyPass.
File: docs/deploying/asgi.rst
ASGI
If you'd like to use an ASGI server you will need to utilise WSGI to
ASGI middleware. The asgirefWsgiToAsgi <https://github.com/django/asgiref#wsgi-to-asgi-adapter>_
adapter is recommended as it integrates with the event loop used for
Flask's :ref:async_await support. You can use the adapter by
wrapping the Flask app,
.. code-block:: python
from asgiref.wsgi import WsgiToAsgi
from flask import Flask
app = Flask(__name__)
...
asgi_app = WsgiToAsgi(app)and then serving the asgi_app with the ASGI server, e.g. usingHypercorn <https://github.com/pgjones/hypercorn>_,
.. sourcecode:: text
$ hypercorn module:asgi_appFile: docs/deploying/eventlet.rst
:orphan:
eventlet
Eventlet is no longer maintained.__ Use :doc:/deploying/gevent instead.
__ https://eventlet.readthedocs.io
File: docs/deploying/gevent.rst
gevent
Prefer using :doc:gunicorn or :doc:uwsgi with gevent workers rather
than using gevent_ directly. Gunicorn and uWSGI provide much more
configurable and production-tested servers.
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. This is
not the same as Python's async/await, or the ASGI server spec.
gevent provides a WSGI server that can handle many connections at once
instead of one per worker process. See :doc:/gevent for more
information about enabling it in your application.
.. _gevent: https://www.gevent.org/
.. _greenlet: https://greenlet.readthedocs.io/en/latest/
Installing
When using gevent, greenlet>=1.0 is required. When using PyPy,
PyPy>=7.3.7 is required.
Create a virtualenv, install your application, then install gevent.
.. code-block:: text
$ cd hello-app
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install geventRunning
To use gevent to serve your application, write a script that imports itsWSGIServer, as well as your app or app factory.
.. code-block:: python
:caption: wsgi.py
from gevent.pywsgi import WSGIServer
from hello import create_app
app = create_app()
http_server = WSGIServer(("127.0.0.1", 8000), app)
http_server.serve_forever().. code-block:: text
$ python wsgi.pyNo output is shown when the server starts.
Binding Externally
gevent 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 to port 80 or 443. Instead, a
reverse proxy such as :doc:nginx or :doc:apache-httpd should be used
in front of gevent.
You can bind to all external IPs on a non-privileged port by using0.0.0.0 in the server arguments shown in the previous section. Don't
do this when using a reverse proxy setup, otherwise it will be possible
to bypass the proxy.
0.0.0.0 is not a valid address to navigate to, you'd use a specific
IP address in your browser.
File: docs/deploying/gunicorn.rst
Gunicorn
Gunicorn_ is a pure Python WSGI server with simple configuration and
multiple worker implementations for performance tuning.
- It tends to integrate easily with hosting platforms.
- It does not support Windows (but does run on WSL).
- It is easy to install as it does not require additional dependencies
or compilation. - It has built-in async worker support using gevent.
This page outlines the basics of running Gunicorn. Be sure to read itsdocumentation_ and use gunicorn --help to understand what features
are available.
.. _Gunicorn: https://gunicorn.org/
.. _documentation: https://docs.gunicorn.org/
Installing
Gunicorn is easy to install, as it does not require external
dependencies or compilation. It runs on Windows only under WSL.
Create a virtualenv, install your application, then installgunicorn.
.. code-block:: text
$ cd hello-app
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install gunicornRunning
The only required argument to Gunicorn tells it how to load your Flask
application. The syntax is {module_import}:{app_variable}.module_import is the dotted import name to the module with your
application. app_variable is the variable with the application. It
can also be a function call (with any arguments) if you're using the
app factory pattern.
.. code-block:: text
# equivalent to 'from hello import app'
$ gunicorn -w 4 'hello:app'
# equivalent to 'from hello import create_app; create_app()'
$ gunicorn -w 4 'hello:create_app()'
Starting gunicorn 20.1.0
Listening at: http://127.0.0.1:8000 (x)
Using worker: sync
Booting worker with pid: x
Booting worker with pid: x
Booting worker with pid: x
Booting worker with pid: xThe -w option specifies the number of processes to run; a starting
value could be CPU * 2. The default is only 1 worker, which is
probably not what you want for the default worker type.
Logs for each request aren't shown by default, only worker info and
errors are shown. To show access logs on stdout, use the--access-logfile=- option.
Binding Externally
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 to port 80 or 443. Instead, a
reverse proxy such as :doc:nginx or :doc:apache-httpd should be used
in front of Gunicorn.
You can bind to all external IPs on a non-privileged port using the-b 0.0.0.0 option. Don't do this when using a reverse proxy setup,
otherwise it will be possible to bypass the proxy.
.. code-block:: text
$ gunicorn -w 4 -b 0.0.0.0 'hello:create_app()'
Listening at: http://0.0.0.0:8000 (x)0.0.0.0 is not a valid address to navigate to, you'd use a specific
IP address in your browser.
Async with gevent
The default sync worker is appropriate for most use cases. If you need numerous,
long running, concurrent connections, Gunicorn provides an asynchronous worker
using gevent_. This is not the same as Python's async/await, or the ASGI
server spec. See :doc:/gevent for more information about enabling it in your
application.
.. _gevent: https://www.gevent.org/
When using gevent, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is
required.
.. code-block:: text
$ gunicorn -k gevent 'hello:create_app()'
Starting gunicorn 20.1.0
Listening at: http://127.0.0.1:8000 (x)
Using worker: gevent
Booting worker with pid: xFile: docs/deploying/index.rst
Deploying to Production
After developing your application, you'll want to make it available
publicly to other users. When you're developing locally, you're probably
using the built-in development server, debugger, and reloader. These
should not be used in production. Instead, you should use a dedicated
WSGI server or hosting platform, some of which will be described here.
"Production" means "not development", which applies whether you're
serving your application publicly to millions of users or privately /
locally to a single user. Do not use the development server when
deploying to production. It is intended for use only during local
development. It is not designed to be particularly secure, stable, or
efficient.
Self-Hosted Options
Flask is a WSGI application. A WSGI server is used to run the
application, converting incoming HTTP requests to the standard WSGI
environ, and converting outgoing WSGI responses to HTTP responses.
The primary goal of these docs is to familiarize you with the concepts
involved in running a WSGI application using a production WSGI server
and HTTP server. There are many WSGI servers and HTTP servers, with many
configuration possibilities. The pages below discuss the most common
servers, and show the basics of running each one. The next section
discusses platforms that can manage this for you.
.. toctree::
:maxdepth: 1
gunicorn
waitress
mod_wsgi
uwsgi
gevent
asgiWSGI servers have HTTP servers built-in. However, a dedicated HTTP
server may be safer, more efficient, or more capable. Putting an HTTP
server in front of the WSGI server is called a "reverse proxy."
.. toctree::
:maxdepth: 1
proxy_fix
nginx
apache-httpdThis list is not exhaustive, and you should evaluate these and other
servers based on your application's needs. Different servers will have
different capabilities, configuration, and support.
Hosting Platforms
There are many services available for hosting web applications without
needing to maintain your own server, networking, domain, etc. Some
services may have a free tier up to a certain time or bandwidth. Many of
these services use one of the WSGI servers described above, or a similar
interface. The links below are for some of the most common platforms,
which have instructions for Flask, WSGI, or Python.
PythonAnywhere <https://help.pythonanywhere.com/pages/Flask/>_Google App Engine <https://cloud.google.com/appengine/docs/standard/python3/building-app>_Google Cloud Run <https://cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-python-service>_AWS Elastic Beanstalk <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create-deploy-python-flask.html>_Microsoft Azure <https://docs.microsoft.com/en-us/azure/app-service/quickstart-python>_
This list is not exhaustive, and you should evaluate these and other
services based on your application's needs. Different services will have
different capabilities, configuration, pricing, and support.
You'll probably need to :doc:proxy_fix when using most hosting
platforms.
File: docs/deploying/mod_wsgi.rst
mod_wsgi
mod_wsgi_ is a WSGI server integrated with the Apache httpd_ server.
The modern mod_wsgi-express_ command makes it easy to configure and
start the server without needing to write Apache httpd configuration.
- Tightly integrated with Apache httpd.
- Supports Windows directly.
- Requires a compiler and the Apache development headers to install.
- Does not require a reverse proxy setup.
This page outlines the basics of running mod_wsgi-express, not the more
complex installation and configuration with httpd. Be sure to read themod_wsgi-express, mod_wsgi, and Apache httpd_ documentation to
understand what features are available.
.. _mod_wsgi-express: https://pypi.org/project/mod-wsgi/
.. _mod_wsgi: https://modwsgi.readthedocs.io/
.. _Apache httpd: https://httpd.apache.org/
Installing
Installing mod_wsgi requires a compiler and the Apache server and
development headers installed. You will get an error if they are not.
How to install them depends on the OS and package manager that you use.
Create a virtualenv, install your application, then installmod_wsgi.
.. code-block:: text
$ cd hello-app
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install mod_wsgiRunning
The only argument to mod_wsgi-express specifies a script containing
your Flask application, which must be called application. You can
write a small script to import your app with this name, or to create it
if using the app factory pattern.
.. code-block:: python
:caption: wsgi.py
from hello import app
application = app.. code-block:: python
:caption: wsgi.py
from hello import create_app
application = create_app()Now run the mod_wsgi-express start-server command.
.. code-block:: text
$ mod_wsgi-express start-server wsgi.py --processes 4The --processes option specifies the number of worker processes to
run; a starting value could be CPU * 2.
Logs for each request aren't show in the terminal. If an error occurs,
its information is written to the error log file shown when starting the
server.
Binding Externally
Unlike the other WSGI servers in these docs, mod_wsgi can be run as
root to bind to privileged ports like 80 and 443. However, it must be
configured to drop permissions to a different user and group for the
worker processes.
For example, if you created a hello user and group, you should
install your virtualenv and application as that user, then tell
mod_wsgi to drop to that user after starting.
.. code-block:: text
$ sudo /home/hello/.venv/bin/mod_wsgi-express start-server \
/home/hello/wsgi.py \
--user hello --group hello --port 80 --processes 4File: docs/deploying/nginx.rst
nginx
nginx_ is a fast, production level HTTP server. When serving your
application with one of the WSGI servers listed in :doc:index, it is
often good or necessary to put a dedicated HTTP server in front of it.
This "reverse proxy" can handle incoming requests, TLS, and other
security and performance concerns better than the WSGI server.
Nginx can be installed using your system package manager, or a pre-built
executable for Windows. Installing and running Nginx itself is outside
the scope of this doc. This page outlines the basics of configuring
Nginx to proxy your application. Be sure to read its documentation to
understand what features are available.
.. _nginx: https://nginx.org/
Domain Name
Acquiring and configuring a domain name is outside the scope of this
doc. In general, you will buy a domain name from a registrar, pay for
server space with a hosting provider, and then point your registrar
at the hosting provider's name servers.
To simulate this, you can also edit your hosts file, located at/etc/hosts on Linux. Add a line that associates a name with the
local IP.
Modern Linux systems may be configured to treat any domain name that
ends with .localhost like this without adding it to the hosts
file.
.. code-block:: python
:caption: /etc/hosts
127.0.0.1 hello.localhostConfiguration
The nginx configuration is located at /etc/nginx/nginx.conf on
Linux. It may be different depending on your operating system. Check the
docs and look for nginx.conf.
Remove or comment out any existing server section. Add a server
section and use the proxy_pass directive to point to the address the
WSGI server is listening on. We'll assume the WSGI server is listening
locally at http://127.0.0.1:8000.
.. code-block:: nginx
:caption: /etc/nginx.conf
server {
listen 80;
server_name _;
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 /;
}
}Then :doc:proxy_fix so that your application uses these headers.
File: docs/deploying/proxy_fix.rst
Tell Flask it is Behind a Proxy
When using a reverse proxy, or many Python hosting platforms, the proxy
will intercept and forward all external requests to the local WSGI
server.
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 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
:doc:werkzeug:middleware/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. Not all proxies set all the headers. Since
incoming headers can be faked, you must set how many proxies are setting
each header so the middleware knows what to trust.
.. code-block:: python
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
)Remember, only apply this middleware if you are behind a proxy, and set
the correct number of proxies that set each header. It can be a security
issue if you get this configuration wrong.