3221: Better PROXY_PROTOCOL r=mergify[bot] a=nextgens

## What type of PR?

Feature

## What does this PR do?

- Disable IMAP, POP3 and Submission by default; see https://nostarttls.secvuln.info/ on why explicit TLS is going away.
- Change the semantic of PROXY_PROTOCOL to make it configurable per port
- fix TLS_FLAVOR=notls not working with snappymail
- fix TLS_PERMISSIVE
- remove KUBERNETES_INGRESS; shouldn't be needed anymore
- update the documentation and the reverse proxy example

### Related issue(s)
- close #3162
- close #3061

## Prerequisites
Before we can consider review and merge, please make sure the following list is done and checked.
If an entry in not applicable, you can check it or remove it from the list.

- [x] In case of feature or enhancement: documentation updated accordingly
- [x] Unless it's docs or a minor change: add [changelog](https://mailu.io/master/contributors/workflow.html#changelog) entry file.


Co-authored-by: Florent Daigniere <nextgens@freenetproject.org>
Co-authored-by: Florent Daigniere <nextgens@users.noreply.github.com>
This commit is contained in:
bors-mailu[bot]
2024-06-09 10:17:32 +00:00
committed by GitHub
15 changed files with 118 additions and 77 deletions

View File

@@ -5,7 +5,7 @@ log_path = /dev/stderr
protocols = imap pop3 lmtp sieve protocols = imap pop3 lmtp sieve
postmaster_address = {{ POSTMASTER }}@{{ DOMAIN }} postmaster_address = {{ POSTMASTER }}@{{ DOMAIN }}
hostname = {{ HOSTNAMES.split(",")[0] }} hostname = {{ HOSTNAMES.split(",")[0] }}
{%- if PROXY_PROTOCOL in ['all', 'all-but-http', 'mail'] %} {%- if PROXY_PROTOCOL_25 %}
submission_host = {{ HOSTNAMES.split(",")[0] }} submission_host = {{ HOSTNAMES.split(",")[0] }}
{% else %} {% else %}
submission_host = {{ FRONT_ADDRESS }} submission_host = {{ FRONT_ADDRESS }}

View File

@@ -22,7 +22,7 @@ http {
{% if REAL_IP_HEADER %} {% if REAL_IP_HEADER %}
real_ip_header {{ REAL_IP_HEADER }}; real_ip_header {{ REAL_IP_HEADER }};
{% elif PROXY_PROTOCOL in ['all', 'all-but-http', 'http'] %} {% elif (PROXY_PROTOCOL_80 or PROXY_PROTOCOL_443) and REAL_IP_FROM %}
real_ip_header proxy_protocol; real_ip_header proxy_protocol;
{% endif %} {% endif %}
@@ -54,14 +54,14 @@ http {
gzip_min_length 1024; gzip_min_length 1024;
# TODO: figure out how to server pre-compressed assets from admin container # TODO: figure out how to server pre-compressed assets from admin container
{% if not KUBERNETES_INGRESS and TLS_FLAVOR in [ 'letsencrypt', 'cert' ] %} {% if PORT_80 and TLS_FLAVOR in [ 'letsencrypt', 'cert' ] %}
# Enable the proxy for certbot if the flavor is letsencrypt and not on kubernetes # Enable the proxy for certbot if the flavor is letsencrypt and not on kubernetes
# #
server { server {
# Listen over HTTP # Listen over HTTP
listen 80{% if PROXY_PROTOCOL in ['all', 'http'] %} proxy_protocol{% endif %}; listen 80{% if PROXY_PROTOCOL_80 %} proxy_protocol{% endif %};
{% if SUBNET6 %} {% if SUBNET6 %}
listen [::]:80{% if PROXY_PROTOCOL in ['all', 'http'] %} proxy_protocol{% endif %}; listen [::]:80{% if PROXY_PROTOCOL_80 %} proxy_protocol{% endif %};
{% endif %} {% endif %}
{% if TLS_FLAVOR in ['letsencrypt', 'mail-letsencrypt'] %} {% if TLS_FLAVOR in ['letsencrypt', 'mail-letsencrypt'] %}
location ^~ /.well-known/acme-challenge/ { location ^~ /.well-known/acme-challenge/ {
@@ -95,18 +95,18 @@ http {
client_max_body_size {{ MESSAGE_SIZE_LIMIT|int + 8388608 }}; client_max_body_size {{ MESSAGE_SIZE_LIMIT|int + 8388608 }};
# Listen on HTTP only in kubernetes or behind reverse proxy # Listen on HTTP only in kubernetes or behind reverse proxy
{% if KUBERNETES_INGRESS or TLS_FLAVOR in [ 'mail-letsencrypt', 'notls', 'mail' ] %} {% if TLS_FLAVOR in [ 'mail-letsencrypt', 'notls', 'mail' ] %}
listen 80{% if PROXY_PROTOCOL in ['all', 'http'] %} proxy_protocol{% endif %}; listen 80{% if PROXY_PROTOCOL_80 %} proxy_protocol{% endif %};
{% if SUBNET6 %} {% if SUBNET6 %}
listen [::]:80{% if PROXY_PROTOCOL in ['all', 'http'] %} proxy_protocol{% endif %}; listen [::]:80{% if PROXY_PROTOCOL_80 %} proxy_protocol{% endif %};
{% endif %} {% endif %}
{% endif %} {% endif %}
# Only enable HTTPS if TLS is enabled with no error and not on kubernetes # Only enable HTTPS if TLS is enabled with no error
{% if not KUBERNETES_INGRESS and TLS and not TLS_ERROR %} {% if TLS_443 and not TLS_ERROR %}
listen 443 ssl http2{% if PROXY_PROTOCOL in ['all', 'all-but-http', 'http'] %} proxy_protocol{% endif %}; listen 443 ssl http2{% if PROXY_PROTOCOL_443 %} proxy_protocol{% endif %};
{% if SUBNET6 %} {% if SUBNET6 %}
listen [::]:443 ssl http2{% if PROXY_PROTOCOL in ['all', 'all-but-http', 'http'] %} proxy_protocol{% endif %}; listen [::]:443 ssl http2{% if PROXY_PROTOCOL_443 %} proxy_protocol{% endif %};
{% endif %} {% endif %}
include /etc/nginx/tls.conf; include /etc/nginx/tls.conf;
@@ -162,7 +162,7 @@ http {
{% endif %} {% endif %}
# If TLS is failing, prevent access to anything except certbot # If TLS is failing, prevent access to anything except certbot
{% if not KUBERNETES_INGRESS and TLS_ERROR and not (TLS_FLAVOR in [ 'mail-letsencrypt', 'mail' ]) %} {% if TLS_ERROR and not (TLS_FLAVOR in [ 'mail-letsencrypt', 'mail' ]) %}
location / { location / {
return 403; return 403;
} }
@@ -315,7 +315,7 @@ mail {
ssl_session_cache shared:SSLMAIL:3m; ssl_session_cache shared:SSLMAIL:3m;
{% endif %} {% endif %}
{% if PROXY_PROTOCOL in ['all', 'all-but-http', 'mail'] and REAL_IP_FROM %}{% for from_ip in REAL_IP_FROM.split(',') %} {% if PROXY_PROTOCOL_25 and REAL_IP_FROM %}{% for from_ip in REAL_IP_FROM.split(',') %}
set_real_ip_from {{ from_ip }}; set_real_ip_from {{ from_ip }};
{% endfor %}{% endif %} {% endfor %}{% endif %}
@@ -324,9 +324,9 @@ mail {
# SMTP is always enabled, to avoid losing emails when TLS is failing # SMTP is always enabled, to avoid losing emails when TLS is failing
server { server {
listen 25{% if PROXY_PROTOCOL in ['all', 'all-but-http', 'mail'] %} proxy_protocol{% endif %}; listen 25{% if PROXY_PROTOCOL_25 %} proxy_protocol{% endif %};
{% if SUBNET6 %} {% if SUBNET6 %}
listen [::]:25{% if PROXY_PROTOCOL in ['all', 'all-but-http', 'mail'] %} proxy_protocol{% endif %}; listen [::]:25{% if PROXY_PROTOCOL_25 %} proxy_protocol{% endif %};
{% endif %} {% endif %}
{% if TLS and not TLS_ERROR %} {% if TLS and not TLS_ERROR %}
{% if TLS_FLAVOR in ['letsencrypt','mail-letsencrypt'] %} {% if TLS_FLAVOR in ['letsencrypt','mail-letsencrypt'] %}

View File

@@ -6,7 +6,7 @@ proxy_hide_header True-Client-IP;
proxy_hide_header CF-Connecting-IP; proxy_hide_header CF-Connecting-IP;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto; proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
{% if (REAL_IP_HEADER or (PROXY_PROTOCOL in ['http', 'all'])) and REAL_IP_FROM %} {% if (REAL_IP_HEADER or (PROXY_PROTOCOL_80 or PROXY_PROTOCOL_443)) and REAL_IP_FROM %}
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-By $realip_remote_addr; proxy_set_header X-Forwarded-By $realip_remote_addr;
{% else %} {% else %}

View File

@@ -70,6 +70,36 @@ with open("/etc/resolv.conf") as handle:
resolver = content[content.index("nameserver") + 1] resolver = content[content.index("nameserver") + 1]
args["RESOLVER"] = f"[{resolver}]" if ":" in resolver else resolver args["RESOLVER"] = f"[{resolver}]" if ":" in resolver else resolver
# Configure PROXY_PROTOCOL
PROTO_MAIL=['25', '110', '995', '143', '993', '587', '465', '4190']
PROTO_ALL_BUT_HTTP=PROTO_MAIL.copy()
PROTO_ALL_BUT_HTTP.extend(['443'])
PROTO_ALL=PROTO_ALL_BUT_HTTP.copy()
PROTO_ALL.extend(['80'])
for item in args.get('PROXY_PROTOCOL', '').split(','):
if item.isdigit():
args[f'PROXY_PROTOCOL_{item}']=True
elif item == 'mail':
for p in PROTO_MAIL: args[f'PROXY_PROTOCOL_{p}']=True
elif item == 'all-but-http':
for p in PROTO_ALL_BUT_HTTP: args[f'PROXY_PROTOCOL_{p}']=True
elif item == 'all':
for p in PROTO_ALL: args[f'PROXY_PROTOCOL_{p}']=True
else:
log.error(f'Not sure what to do with {item} in PROXY_PROTOCOL ({args.get("PROXY_PROTOCOL")})')
PORTS_REQUIRING_TLS=['443', '465', '993', '995']
ALL_PORTS='25,80,443,465,993,995,4190'
for item in args.get('PORTS', ALL_PORTS).split(','):
if item in PORTS_REQUIRING_TLS and args['TLS_FLAVOR'] == 'notls':
continue
args[f'PORT_{item}']=True
if args['TLS_FLAVOR'] != 'notls':
for item in args.get('TLS', ALL_PORTS).split(','):
if item in PORTS_REQUIRING_TLS:
args[f'TLS_{item}']=True
# TLS configuration # TLS configuration
cert_name = args.get("TLS_CERT_FILENAME", "cert.pem") cert_name = args.get("TLS_CERT_FILENAME", "cert.pem")
keypair_name = args.get("TLS_KEYPAIR_FILENAME", "key.pem") keypair_name = args.get("TLS_KEYPAIR_FILENAME", "key.pem")
@@ -129,6 +159,8 @@ if args["TLS"] and not all(os.path.exists(file_path) for file_path in args["TLS"
print("Missing cert or key file, disabling TLS") print("Missing cert or key file, disabling TLS")
args["TLS_ERROR"] = "yes" args["TLS_ERROR"] = "yes"
args['TLS_PERMISSIVE'] = str(args.get('TLS_PERMISSIVE')).lower() not in ('false', 'no')
# Build final configuration paths # Build final configuration paths
conf.jinja("/conf/tls.conf", args, "/etc/nginx/tls.conf") conf.jinja("/conf/tls.conf", args, "/etc/nginx/tls.conf")
conf.jinja("/conf/proxy.conf", args, "/etc/nginx/proxy.conf") conf.jinja("/conf/proxy.conf", args, "/etc/nginx/proxy.conf")

View File

@@ -75,11 +75,12 @@ service anvil {
} }
} }
{%- if PORT_4190 %}
service managesieve-login { service managesieve-login {
executable = managesieve-login executable = managesieve-login
inet_listener sieve { inet_listener sieve {
port = 4190 port = 4190
{%- if PROXY_PROTOCOL in ['all', 'all-but-http', 'mail'] %} {%- if PROXY_PROTOCOL_4190 %}
haproxy = yes haproxy = yes
{% endif %} {% endif %}
} }
@@ -87,6 +88,7 @@ service managesieve-login {
port = 14190 port = 14190
} }
} }
{% endif %}
protocol imap { protocol imap {
mail_max_userip_connections = 20 mail_max_userip_connections = 20
@@ -94,42 +96,46 @@ protocol imap {
} }
service imap-login { service imap-login {
{%- if PORT_143 %}
inet_listener imap { inet_listener imap {
port = 143 port = 143
{%- if PROXY_PROTOCOL in ['all', 'all-but-http', 'mail'] %} {%- if PROXY_PROTOCOL_143 %}
haproxy = yes haproxy = yes
{% endif %} {% endif %}
} }
{% endif %}
{%- if TLS_993 and PORT_993 %}
inet_listener imaps { inet_listener imaps {
port = 993 port = 993
{%- if TLS %}
ssl = yes ssl = yes
{% endif %} {%- if PROXY_PROTOCOL_993 %}
{%- if PROXY_PROTOCOL in ['all', 'all-but-http', 'mail'] %}
haproxy = yes haproxy = yes
{% endif %} {% endif %}
} }
{% endif %}
inet_listener imap-webmail { inet_listener imap-webmail {
port = 10143 port = 10143
} }
} }
service pop3-login { service pop3-login {
{%- if PORT_110 %}
inet_listener pop3 { inet_listener pop3 {
port = 110 port = 110
{%- if PROXY_PROTOCOL in ['all', 'all-but-http', 'mail'] %} {%- if PROXY_PROTOCOL_110 %}
haproxy = yes haproxy = yes
{% endif %} {% endif %}
} }
{% endif %}
{%- if TLS_995 and PORT_995 %}
inet_listener pop3s { inet_listener pop3s {
port = 995 port = 995
{%- if TLS %}
ssl = yes ssl = yes
{% endif %} {%- if PROXY_PROTOCOL_995 %}
{%- if PROXY_PROTOCOL in ['all', 'all-but-http', 'mail'] %}
haproxy = yes haproxy = yes
{% endif %} {% endif %}
} }
{% endif %}
} }
recipient_delimiter = {{ RECIPIENT_DELIMITER }} recipient_delimiter = {{ RECIPIENT_DELIMITER }}
@@ -142,20 +148,25 @@ service lmtp {
service submission-login { service submission-login {
inet_listener submission { inet_listener submission {
{%- if PORT_587 %}
port = 587 port = 587
{%- if PROXY_PROTOCOL in ['all', 'all-but-http', 'mail'] %} {%- if PROXY_PROTOCOL_587 %}
haproxy = yes haproxy = yes
{% endif %}
{%- else %}
# if the section is unset the port is bound anyways
port = 0
{% endif %} {% endif %}
} }
{%- if TLS_465 and PORT_465 %}
inet_listener submissions { inet_listener submissions {
port = 465 port = 465
{%- if TLS %}
ssl = yes ssl = yes
{% endif %} {%- if PROXY_PROTOCOL_465 %}
{%- if PROXY_PROTOCOL in ['all', 'all-but-http', 'mail'] %}
haproxy = yes haproxy = yes
{% endif %} {% endif %}
} }
{% endif %}
inet_listener submission-webmail { inet_listener submission-webmail {
port = 10025 port = 10025
} }

View File

@@ -31,18 +31,14 @@ Sets the ``TLS_FLAVOR`` to one of the following
values: values:
- ``cert`` is the default and requires certificates to be setup manually; - ``cert`` is the default and requires certificates to be setup manually;
- ``letsencrypt`` will use the *Letsencrypt!* CA to generate automatic certificates; - ``letsencrypt`` will use the *Letsencrypt!* CA to obtain certificates automatically;
- ``mail`` is similar to ``cert`` except that TLS will only be served for
emails (IMAP and SMTP), not HTTP (use it behind reverse proxies);
- ``mail-letsencrypt`` is similar to ``letsencrypt`` except that TLS will only be served for
emails (IMAP and SMTP), not HTTP (use it behind reverse proxies);
- ``notls`` will disable TLS, this is not recommended except for testing. - ``notls`` will disable TLS, this is not recommended except for testing.
.. note:: .. note::
When using *Letsencrypt!* you have to make sure that the DNS ``A`` and ``AAAA`` records for the When using *Letsencrypt!* you have to make sure that the DNS ``A`` and ``AAAA`` records for the
all hostnames mentioned in the ``HOSTNAMES`` variable match with the ip addresses of you server. all hostnames mentioned in the ``HOSTNAMES`` variable match with the ip addresses of you server
Or else certificate generation will fail! See also: :ref:`dns_setup`. or else certificate generation will fail! See also: :ref:`dns_setup`.
Bind address Bind address
```````````` ````````````
@@ -91,7 +87,7 @@ Finish setting up TLS
Mailu relies heavily on TLS and must have a key pair and a certificate Mailu relies heavily on TLS and must have a key pair and a certificate
available, at least for the hostname configured in the ``mailu.env`` file. available, at least for the hostname configured in the ``mailu.env`` file.
If you set ``TLS_FLAVOR`` to ``cert`` or ``mail`` then you must create a ``certs`` directory If you set ``TLS_FLAVOR`` to ``cert`` then you must create a ``certs`` directory
in your root path and setup a key-certificate pair there: in your root path and setup a key-certificate pair there:
- ``cert.pem`` contains the certificate (override with ``TLS_CERT_FILENAME``), - ``cert.pem`` contains the certificate (override with ``TLS_CERT_FILENAME``),

View File

@@ -62,8 +62,7 @@ The ``AUTH_RATELIMIT_EXEMPTION`` (default: '') is a comma separated list of netw
CIDRs that won't be subject to any form of rate limiting. Specifying ``0.0.0.0/0, ::/0`` CIDRs that won't be subject to any form of rate limiting. Specifying ``0.0.0.0/0, ::/0``
there is a good way to disable rate limiting altogether. there is a good way to disable rate limiting altogether.
The ``TLS_FLAVOR`` sets how Mailu handles TLS connections. Setting this value to The ``TLS_FLAVOR`` sets how Mailu obtains a x509 certificate. More on :ref:`tls_flavor`.
``notls`` will cause Mailu not to serve any web content! More on :ref:`tls_flavor`.
The ``DEFAULT_SPAM_THRESHOLD`` (default: 80) is the default spam tolerance used when creating a new user. The ``DEFAULT_SPAM_THRESHOLD`` (default: 80) is the default spam tolerance used when creating a new user.
@@ -249,9 +248,20 @@ but slows down the performance of modern devices.
.. _`android handsets older than 7.1.1`: https://community.letsencrypt.org/t/production-chain-changes/150739 .. _`android handsets older than 7.1.1`: https://community.letsencrypt.org/t/production-chain-changes/150739
The ``TLS_PERMISSIVE`` (default: true) setting controls whether ciphers and protocols offered on port 25 for STARTTLS are optimized for maximum compatibility. We **strongly recommend** that you do **not** change this setting on the basis that any encryption beats no encryption. If you are subject to compliance requirements and are not afraid of losing emails as a result of artificially reducing compatibility, set it to 'false'. Keep in mind that servers that are running a software stack old enough to not be compatible with the current TLS requirements will either a) deliver in plaintext b) bounce emails c) silently drop emails; moreover, modern servers will benefit from various downgrade protections (DOWNGRD, RFC7507) making the security argument mostly a moot point. The ``TLS_PERMISSIVE`` (default: true) setting controls whether ciphers and protocols offered on port 25
for STARTTLS are optimized for maximum compatibility. We **strongly recommend** that you do **not** change
this setting on the basis that any encryption beats no encryption. If you are subject to compliance
requirements and are not afraid of losing emails as a result of artificially reducing compatibility,
set it to 'false'. Keep in mind that servers that are running a software stack old enough to not be
compatible with the current TLS requirements will either a) deliver in plaintext b) bounce emails
c) silently drop emails; moreover, modern servers will benefit from various downgrade protections
(DOWNGRD, RFC7507) making the security argument mostly a moot point.
The ``COMPRESSION`` (default: unset) setting controls whether emails are stored compressed at rest on disk. Valid values are ``gz``, ``bz2`` or ``zstd`` and additional settings can be configured via ``COMPRESSION_LEVEL``, see `zlib_save_level`_ for accepted values. If the underlying filesystem supports compression natively you should use it instead of this setting as it will be more efficient and will improve compatibility with 3rd party tools. The ``COMPRESSION`` (default: unset) setting controls whether emails are stored compressed at rest on disk.
Valid values are ``gz``, ``bz2`` or ``zstd`` and additional settings can be configured via
``COMPRESSION_LEVEL``, see `zlib_save_level`_ for accepted values. If the underlying filesystem
supports compression natively you should use it instead of this setting as it will be more efficient
and will improve compatibility with 3rd party tools.
.. _`zlib_save_level`: https://doc.dovecot.org/settings/plugin/zlib-plugin/#plugin_setting-zlib-zlib_save_level .. _`zlib_save_level`: https://doc.dovecot.org/settings/plugin/zlib-plugin/#plugin_setting-zlib-zlib_save_level
@@ -268,13 +278,13 @@ The ``TZ`` sets the timezone Mailu will use. The timezone naming convention usua
.. _`TZ database name`: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones .. _`TZ database name`: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
The ``PROXY_PROTOCOL`` (default: unset) allows the the front container to receive TCP and HTTP connections with
the `PROXY protocol`_ (originally introduced in HAProxy, now also configurable in other proxy servers).
It can be set to:
* ``http`` to accept the ``PROXY`` protocol on nginx's HTTP proxy ports The ``PORTS`` (default: '25,80,443,465,993,995,4190') setting determines which services should be enabled. It is a comma delimited list of ports numbers.
* ``mail`` to accept the ``PROXY`` protocol on nginx's mail proxy ports If you need to re-enable IMAP, POP3 and Submission, you can append '110,143,587' to that list.
* ``all`` to accept the ``PROXY`` protocol on all nginx's HTTP and mail proxy ports
The ``PROXY_PROTOCOL`` (default: unset) setting allows the the front container to receive TCP and HTTP connections with
the `PROXY protocol`_ (originally introduced in HAProxy, now also configurable in other proxy servers).
It can be set to a comma delimited list of ports on which it should be enabled.
.. _`PROXY protocol`: https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt .. _`PROXY protocol`: https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt

View File

@@ -28,11 +28,8 @@ and add a section like follows:
- "--entrypoints.web.address=:http" - "--entrypoints.web.address=:http"
- "--entrypoints.websecure.address=:https" - "--entrypoints.websecure.address=:https"
- "--entrypoints.smtp.address=:smtp" - "--entrypoints.smtp.address=:smtp"
- "--entrypoints.submission.address=:submission"
- "--entrypoints.submissions.address=:submissions" - "--entrypoints.submissions.address=:submissions"
- "--entrypoints.imap.address=:imap"
- "--entrypoints.imaps.address=:imaps" - "--entrypoints.imaps.address=:imaps"
- "--entrypoints.pop3.address=:pop3"
- "--entrypoints.pop3s.address=:pop3s" - "--entrypoints.pop3s.address=:pop3s"
- "--entrypoints.sieve.address=:sieve" - "--entrypoints.sieve.address=:sieve"
# - "--api.insecure=true" # - "--api.insecure=true"
@@ -42,11 +39,8 @@ and add a section like follows:
- "80:80" - "80:80"
- "443:443" - "443:443"
- "465:465" - "465:465"
- "587:587"
- "993:993" - "993:993"
- "995:995" - "995:995"
- "110:110"
- "143:143"
- "4190:4190" - "4190:4190"
# The Web UI (enabled by --api.insecure=true) # The Web UI (enabled by --api.insecure=true)
# - "8080:8080" # - "8080:8080"
@@ -80,36 +74,18 @@ and then add the following to the front section:
- "traefik.tcp.services.smtp.loadbalancer.server.port=25" - "traefik.tcp.services.smtp.loadbalancer.server.port=25"
- "traefik.tcp.services.smtp.loadbalancer.proxyProtocol.version=2" - "traefik.tcp.services.smtp.loadbalancer.proxyProtocol.version=2"
- "traefik.tcp.routers.submission.rule=HostSNI(`*`)"
- "traefik.tcp.routers.submission.entrypoints=submission"
- "traefik.tcp.routers.submission.service=submission"
- "traefik.tcp.services.submission.loadbalancer.server.port=587"
- "traefik.tcp.services.submission.loadbalancer.proxyProtocol.version=2"
- "traefik.tcp.routers.submissions.rule=HostSNI(`*`)" - "traefik.tcp.routers.submissions.rule=HostSNI(`*`)"
- "traefik.tcp.routers.submissions.entrypoints=submissions" - "traefik.tcp.routers.submissions.entrypoints=submissions"
- "traefik.tcp.routers.submissions.service=submissions" - "traefik.tcp.routers.submissions.service=submissions"
- "traefik.tcp.services.submissions.loadbalancer.server.port=465" - "traefik.tcp.services.submissions.loadbalancer.server.port=465"
- "traefik.tcp.services.submissions.loadbalancer.proxyProtocol.version=2" - "traefik.tcp.services.submissions.loadbalancer.proxyProtocol.version=2"
- "traefik.tcp.routers.imap.rule=HostSNI(`*`)"
- "traefik.tcp.routers.imap.entrypoints=imap"
- "traefik.tcp.routers.imap.service=imap"
- "traefik.tcp.services.imap.loadbalancer.server.port=143"
- "traefik.tcp.services.imap.loadbalancer.proxyProtocol.version=2"
- "traefik.tcp.routers.imaps.rule=HostSNI(`*`)" - "traefik.tcp.routers.imaps.rule=HostSNI(`*`)"
- "traefik.tcp.routers.imaps.entrypoints=imaps" - "traefik.tcp.routers.imaps.entrypoints=imaps"
- "traefik.tcp.routers.imaps.service=imaps" - "traefik.tcp.routers.imaps.service=imaps"
- "traefik.tcp.services.imaps.loadbalancer.server.port=993" - "traefik.tcp.services.imaps.loadbalancer.server.port=993"
- "traefik.tcp.services.imaps.loadbalancer.proxyProtocol.version=2" - "traefik.tcp.services.imaps.loadbalancer.proxyProtocol.version=2"
- "traefik.tcp.routers.pop3.rule=HostSNI(`*`)"
- "traefik.tcp.routers.pop3.entrypoints=pop3"
- "traefik.tcp.routers.pop3.service=pop3"
- "traefik.tcp.services.pop3.loadbalancer.server.port=110"
- "traefik.tcp.services.pop3.loadbalancer.proxyProtocol.version=2"
- "traefik.tcp.routers.pop3s.rule=HostSNI(`*`)" - "traefik.tcp.routers.pop3s.rule=HostSNI(`*`)"
- "traefik.tcp.routers.pop3s.entrypoints=pop3s" - "traefik.tcp.routers.pop3s.entrypoints=pop3s"
- "traefik.tcp.routers.pop3s.service=pop3s" - "traefik.tcp.routers.pop3s.service=pop3s"
@@ -129,9 +105,9 @@ in mailu.env:
.. code-block:: docker .. code-block:: docker
REAL_IP_FROM=192.168.203.0/24 REAL_IP_FROM=192.168.203.0/24
PROXY_PROTOCOL=all-but-http PROXY_PROTOCOL=25,443,465,993,995,4190
TRAEFIK_VERSION=v2 TRAEFIK_VERSION=v2
TLS_FLAVOR=mail-letsencrypt TLS_FLAVOR=letsencrypt
WEBROOT_REDIRECT=/sso/login WEBROOT_REDIRECT=/sso/login
Using the above configuration, Traefik will proxy all the traffic related to Mailu's FQDNs without requiring duplicate certificates. Using the above configuration, Traefik will proxy all the traffic related to Mailu's FQDNs without requiring duplicate certificates.

View File

@@ -147,3 +147,5 @@ REJECT_UNLISTED_RECIPIENT=
INITIAL_ADMIN_ACCOUNT=admin INITIAL_ADMIN_ACCOUNT=admin
INITIAL_ADMIN_DOMAIN=mailu.io INITIAL_ADMIN_DOMAIN=mailu.io
INITIAL_ADMIN_PW=FooBar INITIAL_ADMIN_PW=FooBar
PORTS=25,80,443,110,995,143,993,587,465,4190

View File

@@ -142,3 +142,5 @@ REAL_IP_FROM=
# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no) # choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no)
REJECT_UNLISTED_RECIPIENT= REJECT_UNLISTED_RECIPIENT=
PORTS=25,80,443,110,995,143,993,587,465,4190

View File

@@ -142,3 +142,5 @@ REAL_IP_FROM=
# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no) # choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no)
REJECT_UNLISTED_RECIPIENT= REJECT_UNLISTED_RECIPIENT=
PORTS=25,80,443,110,995,143,993,587,465,4190

View File

@@ -142,3 +142,5 @@ REAL_IP_FROM=
# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no) # choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no)
REJECT_UNLISTED_RECIPIENT= REJECT_UNLISTED_RECIPIENT=
PORTS=25,80,443,110,995,143,993,587,465,4190

View File

@@ -142,3 +142,5 @@ REAL_IP_FROM=
# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no) # choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no)
REJECT_UNLISTED_RECIPIENT= REJECT_UNLISTED_RECIPIENT=
PORTS=25,80,443,110,995,143,993,587,465,4190

View File

@@ -0,0 +1,6 @@
Introduce new settings for configuring proxying and TLS. Disable POP3, IMAP and SUBMISSION by default, see https://nostarttls.secvuln.info/
- Drop TLS_FLAVOR=mail-*
- Change the meaning of PROXY_PROTOCOL, introduce PORTS
- Disable POP3, IMAP and SUBMISSION ports by default, to re-enable ensure PORTS include 110, 143 and 587
MANAGESIEVE with implicit TLS is not a thing clients support... so 4190 is enabled by default.

View File

@@ -3,7 +3,7 @@
"IMAP": { "IMAP": {
"host": "{{ FRONT_ADDRESS }}", "host": "{{ FRONT_ADDRESS }}",
"port": 10143, "port": 10143,
"secure": 2, "secure": 3,
"shortLogin": false, "shortLogin": false,
"ssl": { "ssl": {
"verify_peer": false, "verify_peer": false,
@@ -20,7 +20,7 @@
"SMTP": { "SMTP": {
"host": "{{ FRONT_ADDRESS }}", "host": "{{ FRONT_ADDRESS }}",
"port": 10025, "port": 10025,
"secure": 2, "secure": 3,
"shortLogin": false, "shortLogin": false,
"ssl": { "ssl": {
"verify_peer": false, "verify_peer": false,
@@ -37,7 +37,7 @@
"Sieve": { "Sieve": {
"host": "{{ FRONT_ADDRESS }}", "host": "{{ FRONT_ADDRESS }}",
"port": 14190, "port": 14190,
"type": 2, "type": 3,
"shortLogin": false, "shortLogin": false,
"ssl": { "ssl": {
"verify_peer": false, "verify_peer": false,