Skip to content

Commit

Permalink
Try #2300:
Browse files Browse the repository at this point in the history
  • Loading branch information
bors[bot] committed May 4, 2022
2 parents 038412a + cda6059 commit 4c9bf14
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 25 deletions.
61 changes: 47 additions & 14 deletions core/nginx/conf/nginx.conf
Expand Up @@ -286,6 +286,12 @@ mail {
ssl_session_cache shared:SSLMAIL:50m;
{% endif %}

{% if PROXY_PROTOCOL == 'true' %}
{% if REAL_IP_FROM %}{% for from_ip in REAL_IP_FROM.split(',') %}
set_real_ip_from {{ from_ip }};
{% endfor %}{% endif %}
{% endif %}

# Advertise real capabilites of backends (postfix/dovecot)
smtp_capabilities PIPELINING SIZE {{ MESSAGE_SIZE_LIMIT }} ETRN ENHANCEDSTATUSCODES 8BITMIME DSN;
pop3_capabilities TOP UIDL RESP-CODES PIPELINING AUTH-RESP-CODE USER;
Expand All @@ -309,8 +315,8 @@ mail {

# SMTP is always enabled, to avoid losing emails when TLS is failing
server {
listen 25;
listen [::]:25;
listen 25 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
listen [::]:25 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
{% if TLS and not TLS_ERROR %}
{% if TLS_FLAVOR in ['letsencrypt','mail-letsencrypt'] %}
ssl_certificate /certs/letsencrypt/live/mailu/fullchain.pem;
Expand All @@ -329,8 +335,8 @@ mail {
# All other protocols are disabled if TLS is failing
{% if not TLS_ERROR %}
server {
listen 143;
listen [::]:143;
listen 143 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
listen [::]:143 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
{% if TLS %}
starttls only;
{% endif %}
Expand All @@ -340,8 +346,8 @@ mail {
}

server {
listen 110;
listen [::]:110;
listen 110 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
listen [::]:110 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
{% if TLS %}
starttls only;
{% endif %}
Expand All @@ -351,8 +357,8 @@ mail {
}

server {
listen 587;
listen [::]:587;
listen 587 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
listen [::]:587 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
{% if TLS %}
starttls only;
{% endif %}
Expand All @@ -361,26 +367,53 @@ mail {
auth_http_header Auth-Port 587;
}

{% if EMAIL_PROXYED == 'true' %}
# Proxied endpoints (no encryption, but authentication)
server {
listen 11587 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
listen [::]:11587 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
protocol smtp;
smtp_auth plain login;
auth_http_header Auth-Port 587;
}

server {
listen 11143 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
listen [::]:11143 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
protocol imap;
imap_auth plain;
auth_http_header Auth-Port 143;
}

server {
listen 11110 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
listen [::]:11110 {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
protocol pop3;
pop3_auth plain;
auth_http_header Auth-Port 110;
}
{% endif %}

{% if TLS %}
server {
listen 465 ssl;
listen [::]:465 ssl;
listen 465 ssl {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
listen [::]:465 ssl {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
protocol smtp;
smtp_auth plain login;
auth_http_header Auth-Port 465;
}

server {
listen 993 ssl;
listen [::]:993 ssl;
listen 993 ssl {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
listen [::]:993 ssl {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
protocol imap;
imap_auth plain;
auth_http_header Auth-Port 993;
}

server {
listen 995 ssl;
listen [::]:995 ssl;
listen 995 ssl {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
listen [::]:995 ssl {% if PROXY_PROTOCOL == 'true' %}proxy_protocol{% endif %};
protocol pop3;
pop3_auth plain;
auth_http_header Auth-Port 995;
Expand Down
8 changes: 8 additions & 0 deletions docs/configuration.rst
Expand Up @@ -205,6 +205,14 @@ The ``LETSENCRYPT_SHORTCHAIN`` (default: False) setting controls whether we send

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 ``EMAIL_PROXYED`` enables an additional sets of ports that can be used as entrypoint
to Mailu for a mail proxy. Enabling this does not impact the other port sets.
Thi sets of ports (``11587``, ``11143``, ``11110``) have authentication enabled and login throttleing.

The ``PROXY_PROTOCOL`` enables the front container to receive TCP connections with the
`HA PROXY <https://www.haproxy.org/download/2.0/doc/proxy-protocol.txt>`_ protocol, enabling this require all ports sets
with the exception of 80 and 443, to use the ``PROXY`` protocol. Ths requires to have a valid ``REAL_IP_FROM``. See more :ref:`reverse_proxy`.

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.

.. _`TZ database name`: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
Expand Down
24 changes: 13 additions & 11 deletions docs/reverse.rst
@@ -1,3 +1,5 @@
.. _reverse_proxy:

Using an external reverse proxy
===============================

Expand All @@ -13,7 +15,7 @@ There are basically three options, from the most to the least recommended one:

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.
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 <reverse_proxy_headers>` for more information.

Have Mailu Web frontend listen locally
Expand Down Expand Up @@ -57,8 +59,8 @@ Then on your own frontend, point to these local ports. In practice, you only nee
#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.
#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``, the client-autoconfiguration 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
Expand All @@ -68,8 +70,8 @@ Because the admin interface is served as ``/admin``, the Webmail as ``/webmail``
location ~* ^/(admin|sso|static|webdav|webmail|(apple\.)?mobileconfig|(\.well\-known/autoconfig/)?mail/|Autodiscover/Autodiscover) {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass https://localhost:8443;
proxy_set_header X-Real-IP $remote_addr
proxy_pass https://localhost:8443;
}
location /main_app {
Expand All @@ -92,11 +94,11 @@ Because the admin interface is served as ``/admin``, the Webmail as ``/webmail``
.. note:: Please don’t add a ``/`` at the end of the location pattern or all your redirects will fail with 404 because the ``/`` would be missing, and you would have to add it manually to move on

.. 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.
#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).

Expand Down Expand Up @@ -135,7 +137,7 @@ Here is an example configuration :
#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.
#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:

Expand All @@ -154,7 +156,7 @@ Traefik as reverse proxy
As such, many may wish to integrate Mailu into a system which already uses Traefik as its sole ingress/reverse-proxy.

As the ``mailu/front`` container uses Nginx not only for ``HTTP`` forwarding, but also for the mail-protocols like ``SMTP``, ``IMAP``, etc, we need to keep this
container around even when using another ``HTTP`` reverse-proxy. Furthermore, Traefik is neither able to forward non-HTTP, nor can it easily forward HTTPS-to-HTTPS.
container around even when using another ``HTTP`` reverse-proxy. Furthermore, Traefik is neither able to forward non-HTTP, nor can it easily forward HTTPS-to-HTTPS.
This, however, means 3 things:

- ``mailu/front`` needs to listen internally on ``HTTP`` rather than ``HTTPS``
Expand Down Expand Up @@ -187,11 +189,11 @@ To support that use-case, Traefik can request ``SANs`` for your domain. The conf
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.
#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 <reverse_proxy_headers>` for more information.

Expand Down
1 change: 1 addition & 0 deletions towncrier/newsfragments/1472.feature
@@ -0,0 +1 @@
Provide HA Proxy protocol support for email endpoints

0 comments on commit 4c9bf14

Please sign in to comment.