From c3dd7330cb9f4b90bc0897fe48556761f5c1c66d Mon Sep 17 00:00:00 2001 From: Dimitri Huisman Date: Fri, 12 Nov 2021 13:30:31 +0000 Subject: [PATCH 1/2] Update reverse proxy documentation (see #1962). --- docs/configuration.rst | 4 +- docs/reverse.rst | 95 +++++++++++++---------------- towncrier/newsfragments/1962.bugfix | 4 ++ 3 files changed, 51 insertions(+), 52 deletions(-) create mode 100644 towncrier/newsfragments/1962.bugfix diff --git a/docs/configuration.rst b/docs/configuration.rst index ccf49058..8f363a63 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -194,7 +194,9 @@ The ``LETSENCRYPT_SHORTCHAIN`` (default: False) setting controls whether we send .. _`android handsets older than 7.1.1`: https://community.letsencrypt.org/t/production-chain-changes/150739 -The ``REAL_IP_HEADER`` (default: unset) and ``REAL_IP_FROM`` (default: unset) settings controls whether HTTP headers such as ``X-Forwarded-For`` or ``X-Real-IP`` should be trusted. The former should be the name of the HTTP header to extract the client IP address from and the later a comma separated list of IP addresses designing which proxies to trust. If you are using Mailu behind a reverse proxy, you should set both. Setting the former without the later introduces a security vulnerability allowing a potential attacker to spoof his source address. +.. _reverse_proxy_headers: + +The ``REAL_IP_HEADER`` (default: unset) and ``REAL_IP_FROM`` (default: unset) settings controls whether HTTP headers such as ``X-Forwarded-For`` or ``X-Real-IP`` should be trusted. The former should be the name of the HTTP header to extract the client IP address from and the later a comma separated list of IP addresses designating which proxies to trust. If you are using Mailu behind a reverse proxy, you should set both. Setting the former without the later introduces a security vulnerability allowing a potential attacker to spoof his source address. The ``TZ`` sets the timezone Mailu will use. The timezone naming convention usually uses a ``Region/City`` format. See `TZ database name`_ for a list of valid timezones This defaults to ``Etc/UTC``. Warning: if you are observing different timestamps in your log files you should change your hosts timezone to UTC instead of changing TZ to your local timezone. Using UTC allows easy log correlation with remote MTAs. diff --git a/docs/reverse.rst b/docs/reverse.rst index c6b98e4a..6cde55f2 100644 --- a/docs/reverse.rst +++ b/docs/reverse.rst @@ -11,7 +11,10 @@ There are basically three options, from the most to the least recommended one: - `use Traefik in another container as central system-reverse-proxy`_ - `override Mailu Web frontend configuration`_ -All options will require that you modify the ``docker-compose.yml`` file. +All options will require that you modify the ``docker-compose.yml`` and ``mailu.env`` file. + +Mailu must also be configured with the information what header is used by the reverse proxy for passing the remote client IP. +This is configured in the mailu.env file. See the :ref:`configuration reference ` for more information. Have Mailu Web frontend listen locally -------------------------------------- @@ -43,10 +46,19 @@ Then on your own frontend, point to these local ports. In practice, you only nee # [...] here goes your standard configuration location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr proxy_pass https://localhost:8443; } } +.. code-block:: docker + + #mailu.env file + REAL_IP_HEADER=X-Real-IP + REAL_IP_FROM=x.x.x.x,y.y.y.y.y + #x.x.x.x,y.y.y.y.y is the static IP address your reverse proxy uses for connecting to Mailu. + Because the admin interface is served as ``/admin``, the Webmail as ``/webmail``, the single sign on page as ``/sso``, webdav as ``/webdav`` and the static files endpoint as ``/static``, you may also want to use a single virtual host and serve other applications (still Nginx): .. code-block:: nginx @@ -55,8 +67,9 @@ Because the admin interface is served as ``/admin``, the Webmail as ``/webmail`` # [...] here goes your standard configuration location ~ ^/(admin|sso|static|webdav|webmail)/ { - proxy_pass https://localhost:8443; - proxy_set_header Host $http_host; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr + proxy_pass https://localhost:8443; } location /main_app { @@ -76,6 +89,13 @@ Because the admin interface is served as ``/admin``, the Webmail as ``/webmail`` } } +.. code-block:: docker + + #mailu.env file + REAL_IP_HEADER=X-Real-IP + REAL_IP_FROM=x.x.x.x,y.y.y.y.y + #x.x.x.x,y.y.y.y.y is the static IP address your reverse proxy uses for connecting to Mailu. + Finally, you might want to serve the admin interface on a separate virtual host but not expose the admin container directly (have your own HTTPS virtual hosts on top of Mailu, one public for the Webmail and one internal for administration for instance). Here is an example configuration : @@ -88,6 +108,8 @@ Here is an example configuration : # [...] here goes your standard configuration location /webmail { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr proxy_pass https://localhost:8443/webmail; } } @@ -98,12 +120,21 @@ Here is an example configuration : # [...] here goes your standard configuration location /admin { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr proxy_pass https://localhost:8443/admin; proxy_set_header Host $http_host; } } +.. code-block:: docker + + #mailu.env file + REAL_IP_HEADER=X-Real-IP + REAL_IP_FROM=x.x.x.x,y.y.y.y.y + #x.x.x.x,y.y.y.y.y is the static IP address your reverse proxy uses for connecting to Mailu. + Depending on how you access the front server, you might want to add a ``proxy_redirect`` directive to your ``location`` blocks: .. code-block:: nginx @@ -151,7 +182,16 @@ If your Traefik is configured to automatically request certificates from *letsen and this is the ``DOMAIN`` in your ``.env``? To support that use-case, Traefik can request ``SANs`` for your domain. The configuration for this will depend on your Traefik version. ----- +Mailu must also be configured with the information what header is used by the reverse proxy for passing the remote client IP. This is configured in mailu.env: + +.. code-block:: docker + + #mailu.env file + REAL_IP_HEADER=X-Real-IP + REAL_IP_FROM=x.x.x.x,y.y.y.y.y + #x.x.x.x,y.y.y.y.y is the static IP address your reverse proxy uses for connecting to Mailu. + +For more information see the :ref:`configuration reference ` for more information. Traefik 2.x using labels configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -179,53 +219,6 @@ Of course, be sure to define the Certificate Resolver ``foo`` in the static conf Alternatively, you can define SANs in the Traefik static configuration using routers, or in the static configuration using entrypoints. Refer to the Traefik documentation for more details. -Traefik 1.x with TOML configuration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Lets add something like - -.. code-block:: yaml - - [acme] - [[acme.domains]] - main = "your.example.com" # this is the same as $TRAEFIK_DOMAIN! - sans = ["mail.your.example.com", "webmail.your.example.com", "smtp.your.example.com"] - -to your ``traefik.toml``. - ----- - -You might need to clear your ``acme.json``, if a certificate for one of these domains already exists. - -You will need some solution which dumps the certificates in ``acme.json``, so you can include them in the ``mailu/front`` container. -One such example is ``mailu/traefik-certdumper``, which has been adapted for use in Mailu. You can add it to your ``docker-compose.yml`` like: - -.. code-block:: yaml - - certdumper: - restart: always - image: mailu/traefik-certdumper:$VERSION - environment: - # Make sure this is the same as the main=-domain in traefik.toml - # !!! Also don’t forget to add "TRAEFIK_DOMAIN=[...]" to your .env! - - DOMAIN=$TRAEFIK_DOMAIN - volumes: - # Folder, which contains the acme.json - - "/data/traefik:/traefik" - # Folder, where cert.pem and key.pem will be written - - "/data/mailu/certs:/output" - - -Assuming you have ``volume-mounted`` your ``acme.json`` put to ``/data/traefik`` on your host. The dumper will then write out ``/data/mailu/certs/cert.pem`` and ``/data/mailu/certs/key.pem`` whenever ``acme.json`` is updated. -Yay! Now let’s mount this to our ``front`` container like: - -.. code-block:: yaml - - volumes: - - /data/mailu/certs:/certs - -This works, because we set ``TLS_FLAVOR=mail``, which picks up the key-certificate pair (e.g., ``cert.pem`` and ``key.pem``) from the certs folder in the root path (``/certs/``). - .. _`Traefik`: https://traefik.io/ Override Mailu configuration diff --git a/towncrier/newsfragments/1962.bugfix b/towncrier/newsfragments/1962.bugfix new file mode 100644 index 00000000..423271a9 --- /dev/null +++ b/towncrier/newsfragments/1962.bugfix @@ -0,0 +1,4 @@ +Reverse proxy documentation has been updated to reflect new security hardening from PR#1959. +If you do not set the required header, Mailu will not have access to the real ip address of the connecting client. +This means that rate limiting will not properly work. You can also not use fail2ban. +It is very important to set this header when using a reverse proxy. \ No newline at end of file From 5911ee605658328bbba375ecfab17bcd63bce54e Mon Sep 17 00:00:00 2001 From: Dimitri Huisman Date: Sat, 13 Nov 2021 14:35:23 +0000 Subject: [PATCH 2/2] Reworded changelog that it is very important to set the new configuration parameters --- towncrier/newsfragments/1962.bugfix | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/towncrier/newsfragments/1962.bugfix b/towncrier/newsfragments/1962.bugfix index 423271a9..70b2aa72 100644 --- a/towncrier/newsfragments/1962.bugfix +++ b/towncrier/newsfragments/1962.bugfix @@ -1,4 +1,5 @@ Reverse proxy documentation has been updated to reflect new security hardening from PR#1959. -If you do not set the required header, Mailu will not have access to the real ip address of the connecting client. +If you do not set the configuration parameters in Mailu what reverse proxy header to trust, +then Mailu will not have access to the real ip address of the connecting client. This means that rate limiting will not properly work. You can also not use fail2ban. -It is very important to set this header when using a reverse proxy. \ No newline at end of file +It is very important to configure this when using a reverse proxy.