| .. index:: reverse, proxy, TLS, SSL, https |
| |
| .. _using-behind-a-reverse-proxy: |
| |
| ============================ |
| Using Behind a Reverse Proxy |
| ============================ |
| |
| Often people will set up "pure Python" web servers behind reverse proxies, |
| especially if they need TLS support (Waitress does not natively support TLS). |
| Even if you don't need TLS support, it's not uncommon to see Waitress and |
| other pure-Python web servers set up to only handle requests behind a reverse proxy; |
| these proxies often have lots of useful deployment knobs. |
| |
| If you're using Waitress behind a reverse proxy, you'll almost always want |
| your reverse proxy to pass along the ``Host`` header sent by the client to |
| Waitress, in either case, as it will be used by most applications to generate |
| correct URLs. You may also use the proxy headers if passing ``Host`` directly |
| is not possible, or there are multiple proxies involved. |
| |
| For example, when using nginx as a reverse proxy, you might add the following |
| lines in a ``location`` section. |
| |
| .. code-block:: nginx |
| |
| proxy_set_header Host $host; |
| |
| The Apache directive named ``ProxyPreserveHost`` does something similar when |
| used as a reverse proxy. |
| |
| Unfortunately, even if you pass the ``Host`` header, the Host header does not |
| contain enough information to regenerate the original URL sent by the client. |
| For example, if your reverse proxy accepts HTTPS requests (and therefore URLs |
| which start with ``https://``), the URLs generated by your application when |
| used behind a reverse proxy served by Waitress might inappropriately be |
| ``http://foo`` rather than ``https://foo``. To fix this, you'll want to |
| change the ``wsgi.url_scheme`` in the WSGI environment before it reaches your |
| application. You can do this in one of three ways: |
| |
| 1. You can pass a ``url_scheme`` configuration variable to the |
| ``waitress.serve`` function. |
| |
| 2. You can pass certain well known proxy headers from your proxy server and |
| use waitress's ``trusted_proxy`` support to automatically configure the |
| WSGI environment. |
| |
| Using ``url_scheme`` to set ``wsgi.url_scheme`` |
| ----------------------------------------------- |
| |
| You can have the Waitress server use the ``https`` url scheme by default.: |
| |
| .. code-block:: python |
| |
| from waitress import serve |
| serve(wsgiapp, listen='0.0.0.0:8080', url_scheme='https') |
| |
| This works if all URLs generated by your application should use the ``https`` |
| scheme. |
| |
| Passing the proxy headers to setup the WSGI environment |
| ------------------------------------------------------- |
| |
| If your proxy accepts both HTTP and HTTPS URLs, and you want your application |
| to generate the appropriate url based on the incoming scheme, you'll want to |
| pass waitress ``X-Forwarded-Proto``, however Waitress is also able to update |
| the environment using ``X-Forwarded-Proto``, ``X-Forwarded-For``, |
| ``X-Forwarded-Host``, and ``X-Forwarded-Port``:: |
| |
| proxy_set_header X-Forwarded-Proto $scheme; |
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
| proxy_set_header X-Forwarded-Host $host:$server_port; |
| proxy_set_header X-Forwarded-Port $server_port; |
| |
| when using Apache, ``mod_proxy`` automatically forwards the following headers:: |
| |
| X-Forwarded-For |
| X-Forwarded-Host |
| X-Forwarded-Server |
| |
| You will also want to add to Apache:: |
| |
| RequestHeader set X-Forwarded-Proto https |
| |
| Configure waitress's ``trusted_proxy_headers`` as appropriate:: |
| |
| trusted_proxy_headers = "x-forwarded-for x-forwarded-host x-forwarded-proto x-forwarded-port" |
| |
| At this point waitress will set up the WSGI environment using the information |
| specified in the trusted proxy headers. This will setup the following |
| variables:: |
| |
| HTTP_HOST |
| SERVER_NAME |
| SERVER_PORT |
| REMOTE_ADDR |
| REMOTE_PORT (if available) |
| wsgi.url_scheme |
| |
| Waitress also has support for the `Forwarded (RFC7239) HTTP header |
| <https://tools.ietf.org/html/rfc7239>`_ which is better defined than the ad-hoc |
| ``X-Forwarded-*``, however support is not nearly as widespread yet. |
| ``Forwarded`` supports similar functionality as the different individual |
| headers, and is mutually exclusive to using the ``X-Forwarded-*`` headers. |
| |
| To configure waitress to use the ``Forwarded`` header, set:: |
| |
| trusted_proxy_headers = "forwarded" |
| |
| .. note:: |
| |
| You must also configure the Waitress server's ``trusted_proxy`` to |
| contain the IP address of the proxy. |
| |
| |
| Using ``url_prefix`` to influence ``SCRIPT_NAME`` and ``PATH_INFO`` |
| ------------------------------------------------------------------- |
| |
| You can have the Waitress server use a particular url prefix by default for all |
| URLs generated by downstream applications that take ``SCRIPT_NAME`` into |
| account.: |
| |
| .. code-block:: python |
| |
| from waitress import serve |
| serve(wsgiapp, listen='0.0.0.0:8080', url_prefix='/foo') |
| |
| Setting this to any value except the empty string will cause the WSGI |
| ``SCRIPT_NAME`` value to be that value, minus any trailing slashes you add, and |
| it will cause the ``PATH_INFO`` of any request which is prefixed with this |
| value to be stripped of the prefix. This is useful in proxying scenarios where |
| you wish to forward all traffic to a Waitress server but need URLs generated by |
| downstream applications to be prefixed with a particular path segment. |