summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/d2/cgi.rst88
-rw-r--r--docs/d2/daemon.rst0
-rw-r--r--docs/d2/fastcgi.rst116
-rw-r--r--docs/d2/index.rst33
-rw-r--r--docs/d2/proxying.rst104
-rw-r--r--docs/d2/static.rst32
-rw-r--r--docs/d2/unix-socket.rst0
-rw-r--r--example.py26
-rw-r--r--httpd-wsgi.conf30
-rw-r--r--nginx-wsgi.conf20
10 files changed, 449 insertions, 0 deletions
diff --git a/docs/d2/cgi.rst b/docs/d2/cgi.rst
new file mode 100644
index 00000000..11cda8db
--- /dev/null
+++ b/docs/d2/cgi.rst
@@ -0,0 +1,88 @@
+CGI (Deprecated)
+================
+
+.. warning::
+
+ This is documented for historic reasons, but you should not deploy
+ with this method in a modern setting. It is not efficient and is
+ difficult to debug. It is better to use a WSGI server.
+
+`CGI`_ is an old protocol for executing a web application. A script is
+executed with environment variables describing the request. The script
+prints to ``stdout`` to generate a response. CGI is inefficient because
+it requires starting the Python process for every request, there is no
+persistent server process.
+
+These instructions are for Apache. Nginx does not support CGI.
+
+Python
+------
+
+Create a virtualenv.
+
+.. code-block:: text
+
+ $ python3 -m venv venv
+ $ ./venv/bin/pip install -r requirements.txt
+
+Create a Python script that imports your application and runs it with
+:class:`wsgiref.handlers.CGIHandler`. The comment on the first line
+tells the script to run using the project's virtualenv.
+
+.. code-block:: python
+ :caption: /home/project/code/cgi_handler.py
+
+ #!/home/project/venv/bin/python
+ from wsgiref.handlers import CGIHandler
+ from project import app
+
+ CGIHandler().run(app)
+
+Mark the script executable:
+
+.. code-block:: text
+
+ $ chmod +x cgi_handler.py
+
+Apache
+------
+
+Enable the CGI module by uncommenting or adding the following lines:
+
+.. code-block:: apache
+ :caption: /etc/httpd/conf/httpd.conf
+
+ <IfModule !mpm_prefork_module>
+ LoadModule cgid_module modules/mod_cgid.so
+ </IfModule>
+ <IfModule mpm_prefork_module>
+ LoadModule cgi_module modules/mod_cgi.so
+ </IfModule>
+
+Configure Apache using the `ScriptAlias`_ directive. This maps a URL
+path to the ``cgi_handler.py`` executable.
+
+.. code-block:: apache
+
+ Alias /static/ /home/project/code/static/
+
+ ScriptAlias / /home/project/code/cgi_handler.py/
+
+ <Directory /home/project/code>
+ <Files cgi_handler.py>
+ Require all granted
+ </Files>
+ </Directory>
+
+ <Directory /home/project/code/static>
+ Require all granted
+ </Directory>
+
+To serve the application under a path, change the ``ScriptAlias``:
+
+.. code-block:: apache
+
+ ScriptAlias /app /home/project/code/cgi_handler.py
+
+.. _CGI: https://en.wikipedia.org/wiki/Common_Gateway_Interface
+.. _ScriptAlias: https://httpd.apache.org/docs/current/mod/mod_alias.html#scriptalias
diff --git a/docs/d2/daemon.rst b/docs/d2/daemon.rst
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/docs/d2/daemon.rst
diff --git a/docs/d2/fastcgi.rst b/docs/d2/fastcgi.rst
new file mode 100644
index 00000000..cf8d93de
--- /dev/null
+++ b/docs/d2/fastcgi.rst
@@ -0,0 +1,116 @@
+FastCGI (Deprecated)
+====================
+
+.. warning::
+
+ This is documented for historic reasons, but you should not deploy
+ with this method in a modern setting. It is better to use a WSGI
+ server.
+
+`FastCGI`_ is an improvement on CGI that keeps the application process
+running and communicates with a binary protocol. While it is more
+efficient than CGI, it is not common or well supported in Python. You
+will have a better experience using a WSGI server instead.
+
+
+Python
+------
+
+Create a virtualenv. Install `flup`_, which provides a FastCGI server
+implementation.
+
+.. code-block:: text
+
+ $ python3 -m venv venv
+ $ ./venv/bin/pip install -r requirements.txt
+ $ ./venv/bin/pip install flup
+
+Create a Python script that imports your application and runs it with
+:class:`flup.server.fcgi.WSGIServer`.
+
+.. code-block:: python
+ :caption: /home/project/code/fcgi_handler.py
+
+ from flup.server.fcgi import WSGIHandler
+ from project import app
+
+ WSGIHandler(app, bindAddress=("localhost", 8080)).run()
+
+Run the application. Flup doesn't output anything, so you'll just see
+a blank space after it starts. It needs to remain running in the
+background, see :doc:`daemon` for more robust solutions.
+
+.. code-block:: text
+
+ $ python3 fcgi_handler.py
+
+
+Nginx
+-----
+
+Nginx has FastCGI support built in, but requires some configuration to
+set ``PATH_INFO`` and ``SCRIPT_NAME`` correctly.
+
+To serve at the root:
+
+.. code-block:: nginx
+
+ location /static/ {
+ alias /home/project/code/static;
+ }
+
+ location / {
+ include fastcgi_params;
+ fastcgi_param SCRIPT_NAME "";
+ fastcgi_param PATH_INFO $fastcgi_script_name;
+ fastcgi_pass localhost:8080;
+ }
+
+When serving under a path, use ``fastcgi_split_path_info`` to split
+``PATH_INFO`` from ``SCRIPT_NAME``.
+
+.. code-block:: nginx
+
+ location /fcgi {
+ fastcgi_split_path_info ^(/fcgi)(.*)$;
+ include fastcgi_params;
+ fastcgi_param PATH_INFO $fastcgi_path_info;
+ fastcgi_pass localhost:8080;
+ }
+
+Apache
+------
+
+The modern way to use FastCGI in Apache is to enable mod_proxy_fcgi,
+which extends mod_proxy to understand the FastCGI protocol. Uncomment
+or add the following lines:
+
+.. code-block:: apache
+ :caption: /etc/httpd/conf/httpd.conf
+
+ LoadModule proxy_module modules/mod_proxy.so
+ LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
+
+Apache requires some configuration to set ``PATH_INFO`` and
+``SCRIPT_NAME`` correctly.
+
+To serve the application at the root:
+
+.. code-block:: apache
+
+ Alias /static/ /home/project/code/static/
+
+ ProxyPass / fcgi://localhost:8080/
+ ProxyFCGISetEnvIf true SCRIPT_NAME
+ ProxyFCGISetEnvIf true proxy-fcgi-pathinfo full
+
+To serve under a path:
+
+.. code-block:: apache
+
+ ProxyPass /fcgi fcgi://localhost:8080
+ ProxyFCGISetEnvIf true SCRIPT_NAME /fcgi
+ ProxyFCGISetEnvIf true proxy-fcgi-pathinfo full
+
+.. _FastCGI: https://en.wikipedia.org/wiki/FastCGI
+.. _flup: https://pypi.org/project/flup/
diff --git a/docs/d2/index.rst b/docs/d2/index.rst
new file mode 100644
index 00000000..cb749845
--- /dev/null
+++ b/docs/d2/index.rst
@@ -0,0 +1,33 @@
+Deploying to Production
+=======================
+
+While lightweight and easy to use, **Werkzeug's built-in development
+server is not suitable for a production deployment**. It is not designed
+to be particularly secure, stable, or efficient, and is may be missing
+HTTP features that a production server should have. Instead, you should
+use a production WSGI server and HTTP server.
+
+Basic instructions for common WSGI and HTTP servers are listed here. If
+you want to use a server not listed here, look up the server's
+documentation about how to use a WSGI app with it, or how to use it as
+a reverse proxy.
+
+.. toctree::
+
+ proxying
+ uwsgi
+ mod_wsgi
+
+.. toctree::
+ :caption: Topics:
+
+ static
+ unix-socket
+ app-config
+ daemon
+
+.. toctree::
+ :caption: Deprecated:
+
+ fastcgi
+ cgi
diff --git a/docs/d2/proxying.rst b/docs/d2/proxying.rst
new file mode 100644
index 00000000..8cb69a6f
--- /dev/null
+++ b/docs/d2/proxying.rst
@@ -0,0 +1,104 @@
+Proxying
+========
+
+When you run many common WSGI servers, they start a local HTTP server
+listening on a TCP port like 8000. Despite providing this built-in HTTP
+server, it is preferable to place a dedicated HTTP server between the
+local server and the internet. This is because a dedicated HTTP server
+is good at handling the behavior of HTTP and TLS, while a WSGI server is
+good at managing a WSGI application.
+
+The examples below use `Gunicorn`_, but the instructions should be
+similar for any WSGI server. Consult your chosen WSGI server's docs for
+more information.
+
+Python
+------
+
+Create a virtualenv. Install a WSGI server such as `Gunicorn`_.
+
+.. code-block:: text
+
+ $ python3 -m venv venv
+ $ ./venv/bin/pip install -r requirements.txt
+ $ ./venv/bin/pip install gunicorn
+
+The HTTP will set some headers to let the application know how it's
+connected to the outside world. The WSGI app needs to be wrapped with
+the :class:`~werkzeug.middleware.proxy_fix.ProxyFix` middleware to use
+this information. Create a Python file to configure the app.
+
+.. code-block:: python
+ :caption: /home/project/wsgi_setup.py
+
+ from werkzeug.middleware.proxy_fix import ProxyFix
+ from project import app
+
+ app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
+
+Run Gunicorn with some workers and point it at the configured app. It
+needs to remain running in the background, see :doc:`daemon`.
+
+.. code-block:: text
+
+ $ gunicorn -b localhost:8000 -w 4 wsgi_setup:app
+
+
+Nginx
+-----
+
+To serve at the root:
+
+.. code-block:: nginx
+
+ location /static/ {
+ alias /home/project/code/static;
+ }
+
+ location / {
+ }
+
+When serving under a path, use ``fastcgi_split_path_info`` to split
+``PATH_INFO`` from ``SCRIPT_NAME``.
+
+.. code-block:: nginx
+
+ location /api {
+ proxy_set_header X-Forwarded-Host $host:$server_port;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_pass http://localhost:8080;
+ proxy_redirect off;
+ }
+
+Apache
+------
+
+To enable mod_proxy, uncomment or add the following line:
+
+.. code-block:: apache
+ :caption: /etc/httpd/conf/httpd.conf
+
+ LoadModule proxy_module modules/mod_proxy.so
+
+Apache requires some configuration to set ``PATH_INFO`` and
+``SCRIPT_NAME`` correctly.
+
+To serve the application at the root:
+
+.. code-block:: apache
+
+ Alias /static/ /home/project/code/static/
+
+ ProxyPass / fcgi://localhost:8080/
+ ProxyFCGISetEnvIf true SCRIPT_NAME
+ ProxyFCGISetEnvIf true proxy-fcgi-pathinfo full
+
+To serve under a path:
+
+.. code-block:: apache
+
+ ProxyPass /fcgi fcgi://localhost:8080
+ ProxyFCGISetEnvIf true SCRIPT_NAME /fcgi
+ ProxyFCGISetEnvIf true proxy-fcgi-pathinfo full
+
+.. _Gunicorn:: https://gunicorn.org/
diff --git a/docs/d2/static.rst b/docs/d2/static.rst
new file mode 100644
index 00000000..4b3a6c54
--- /dev/null
+++ b/docs/d2/static.rst
@@ -0,0 +1,32 @@
+Static Files
+============
+
+If your application has static files such as JavaScript, CSS, and
+images, it will be more efficient to let the HTTP server serve them
+directly rather than going through the Python application.
+
+Assuming the static files are expected to be available under the
+``/static/`` URL, and are stored at ``/home/project/code/static/``, the
+HTTP server can be configured to serve them directly.
+
+
+Nginx
+-----
+
+Within the ``server`` block, add the following:
+
+.. code-block:: nginx
+
+ location /static {
+ alias /home/project/code/static;
+ }
+
+
+Apache
+------
+
+Add the following to the config:
+
+.. code-block::
+
+ Alias /static/ /home/project/code/static/
diff --git a/docs/d2/unix-socket.rst b/docs/d2/unix-socket.rst
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/docs/d2/unix-socket.rst
diff --git a/example.py b/example.py
new file mode 100644
index 00000000..536efee1
--- /dev/null
+++ b/example.py
@@ -0,0 +1,26 @@
+from pprint import pformat
+
+from werkzeug.exceptions import NotFound
+from werkzeug.routing import Map
+from werkzeug.routing import Rule
+from werkzeug.wrappers import Request
+from werkzeug.wrappers import Response
+
+map = Map(rules=[Rule("/test", endpoint="test")])
+
+
+@Request.application
+def app(request):
+ adapter = map.bind_to_environ(request.environ)
+ try:
+ current = adapter.match()
+ except NotFound:
+ current = None
+ url = adapter.build("test")
+ return Response(f"{pformat(request.environ)}\n{current}\n{url}")
+
+
+if __name__ == "__main__":
+ from flup.server.fcgi import WSGIServer
+
+ WSGIServer(app, bindAddress="fcgi.sock", umask=0o111).run()
diff --git a/httpd-wsgi.conf b/httpd-wsgi.conf
new file mode 100644
index 00000000..55259f37
--- /dev/null
+++ b/httpd-wsgi.conf
@@ -0,0 +1,30 @@
+Alias /static/ /home/david/Projects/werkzeug/static/
+
+ScriptAlias /cgi /home/david/Projects/werkzeug/example.py
+
+#ProxyPass /fcgi unix:/home/david/Projects/werkzeug/fcgi.sock|fcgi://localhost
+ProxyPass /fcgi fcgi://localhost:8080
+ProxyFCGISetEnvIf true SCRIPT_NAME
+ProxyFCGISetEnvIf true proxy-fcgi-pathinfo full
+
+#ProxyPass /http unix:/home/david/Projects/werkzeug/gunicorn.sock|http://localhost/http
+ProxyPass /http http://localhost:8080/http
+
+#ProxyPass /uwsgi unix:/home/david/Projects/werkzeug/uwsgi.sock|uwsgi://localhost
+ProxyPass /uwsgi uwsgi://localhost:8080
+
+LoadModule wsgi_module modules/mod_wsgi.so
+WSGIDaemonProcess example python-home=/home/david/.virtualenvs/werkzeug
+WSGIProcessGroup example
+WSGIApplicationGroup %{SERVER}
+WSGIScriptAlias /wsgi /home/david/Projects/werkzeug/example.py
+
+<Directory /home/david/Projects/werkzeug>
+ <Files example.py>
+ Require all granted
+ </Files>
+</Directory>
+
+<Directory /home/david/Projects/werkzeug/static>
+ Require all granted
+</Directory>
diff --git a/nginx-wsgi.conf b/nginx-wsgi.conf
new file mode 100644
index 00000000..096e41a7
--- /dev/null
+++ b/nginx-wsgi.conf
@@ -0,0 +1,20 @@
+location /fcgi {
+ fastcgi_split_path_info ^(/fcgi)(.*)$;
+ include fastcgi_params;
+ fastcgi_param PATH_INFO $fastcgi_path_info;
+ fastcgi_pass localhost:8080;
+}
+
+location /http {
+ proxy_set_header X-Forwarded-Host $host:$server_port;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_pass http://localhost:8080;
+ proxy_redirect off;
+}
+
+location /uwsgi {
+ include uwsgi_params;
+ uwsgi_param X-Forwarded-Host $host:$server_port;
+ uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
+ uwsgi_pass localhost:8080;
+}