diff options
Diffstat (limited to 'docs/d2')
| -rw-r--r-- | docs/d2/cgi.rst | 88 | ||||
| -rw-r--r-- | docs/d2/daemon.rst | 0 | ||||
| -rw-r--r-- | docs/d2/fastcgi.rst | 116 | ||||
| -rw-r--r-- | docs/d2/index.rst | 33 | ||||
| -rw-r--r-- | docs/d2/proxying.rst | 104 | ||||
| -rw-r--r-- | docs/d2/static.rst | 32 | ||||
| -rw-r--r-- | docs/d2/unix-socket.rst | 0 |
7 files changed, 373 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 |
