mirror of
https://github.com/optim-enterprises-bv/Mailu.git
synced 2025-12-03 14:44:00 +00:00
260 lines
10 KiB
ReStructuredText
260 lines
10 KiB
ReStructuredText
Using an external reverse proxy
|
||
===============================
|
||
|
||
One of Mailu's use cases is as part of a larger services platform, where maybe
|
||
other Web services are available than just Mailu Webmail and Admin interfaces.
|
||
|
||
In such a configuration, one would usually run a frontend reverse proxy to serve all
|
||
Web contents based on criteria like the requested hostname (virtual hosts)
|
||
and/or the requested path.
|
||
|
||
The Mailu Admin Web frontend is disabled in the default setup for security reasons,
|
||
it is however expected that most users will enable it at some point. Also, due
|
||
to the Docker Compose configuration structure, it is impossible for us to facilitate
|
||
disabling the Web frontend with a configuration variable. This guide was written to
|
||
help users setup such an architecture.
|
||
|
||
There are basically three options, from the most to the least recommended one:
|
||
|
||
- `have Mailu Web frontend listen locally and use your own Web frontend on top of it`_
|
||
- `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`` 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 <reverse_proxy_headers>` for more information.
|
||
|
||
Have Mailu Web frontend listen locally
|
||
--------------------------------------
|
||
|
||
The simplest and safest option is to modify the port forwards for Mailu Web frontend and have your own frontend point there.
|
||
For instance, in the ``front`` section of Mailu ``docker-compose.yml``, use local ports 8080 and 8443 respectively for HTTP and HTTPS:
|
||
|
||
.. code-block:: yaml
|
||
|
||
front:
|
||
# build: nginx
|
||
image: mailu/nginx:$VERSION
|
||
restart: always
|
||
env_file: .env
|
||
ports:
|
||
- "127.0.0.1:8080:80"
|
||
- "127.0.0.1:8443:443"
|
||
...
|
||
volumes:
|
||
- "$ROOT/certs:/certs"
|
||
|
||
Then on your own frontend, point to these local ports. In practice, you only need to point to the HTTPS port
|
||
(as the HTTP port simply redirects there). Here is an example Nginx configuration:
|
||
|
||
.. code-block:: nginx
|
||
|
||
server {
|
||
listen 443;
|
||
server_name mymailhost.tld;
|
||
|
||
# [...] 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``, 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
|
||
|
||
server {
|
||
# [...] here goes your standard configuration
|
||
|
||
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;
|
||
}
|
||
|
||
location /main_app {
|
||
proxy_pass https://some-host;
|
||
}
|
||
|
||
location /other_app {
|
||
proxy_pass https://some-other-host;
|
||
}
|
||
|
||
location /local_app {
|
||
root /path/to/your/files;
|
||
}
|
||
|
||
location / {
|
||
return 301 $scheme://$host/main_app;
|
||
}
|
||
}
|
||
|
||
.. 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.
|
||
|
||
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 :
|
||
|
||
.. code-block:: nginx
|
||
|
||
server {
|
||
listen <public_ip>:443;
|
||
server_name external.example.com;
|
||
# [...] 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;
|
||
}
|
||
}
|
||
|
||
server {
|
||
listen <internal_ip>:443;
|
||
server_name internal.example.com;
|
||
# [...] 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
|
||
|
||
proxy_redirect https://localhost https://example.com;
|
||
|
||
This will stop redirects (301 and 302) sent by the Webmail, nginx front and admin interface from sending you to ``localhost``.
|
||
|
||
.. _traefik_proxy:
|
||
|
||
Traefik as reverse proxy
|
||
------------------------
|
||
|
||
`Traefik`_ is a popular reverse-proxy aimed at containerized systems.
|
||
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.
|
||
|
||
This, however, means 3 things:
|
||
|
||
- ``mailu/front`` needs to listen internally on ``HTTP`` rather than ``HTTPS``
|
||
- ``mailu/front`` is not exposed to the outside world on ``HTTP``
|
||
- ``mailu/front`` still needs ``SSL`` certificates (here, we assume ``letsencrypt``) for a well-behaved mail service
|
||
|
||
This makes the setup with Traefik a bit harder: Traefik saves its certificates in a proprietary *JSON* file, which is not readable
|
||
by Nginx in the ``front``-container. To solve this, your ``acme.json`` needs to be exposed to the host or a ``docker-volume``.
|
||
It will then be read by a script in another container, which will dump the certificates as ``PEM`` files, readable for
|
||
Nginx. The ``front`` container will automatically reload Nginx whenever these certificates change.
|
||
|
||
To set this up, first set ``TLS_FLAVOR=mail`` in your ``.env``. This tells ``mailu/front`` not to try to request certificates using ``letsencrypt``,
|
||
but to read provided certificates, and use them only for mail-protocols, not for ``HTTP``.
|
||
Next, in your ``docker-compose.yml``, comment out the ``port`` lines of the ``front`` section for port ``…:80`` and ``…:443``.
|
||
Add the respective Traefik labels for your domain/configuration, like
|
||
|
||
.. code-block:: yaml
|
||
|
||
labels:
|
||
- "traefik.enable=true"
|
||
- "traefik.port=80"
|
||
- "traefik.frontend.rule=Host:$TRAEFIK_DOMAIN"
|
||
|
||
.. note:: Please don’t forget to add ``TRAEFIK_DOMAIN=[...]`` TO YOUR ``.env``
|
||
|
||
If your Traefik is configured to automatically request certificates from *letsencrypt*, then you’ll have a certificate
|
||
for ``mail.your.example.com`` now. However, ``mail.your.example.com`` might only be the location where you want the Mailu web-interfaces
|
||
to live — your mail should be sent/received from ``your.example.com``, 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 <reverse_proxy_headers>` for more information.
|
||
|
||
Traefik 2.x using labels configuration
|
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||
|
||
Add the appropriate labels for your domain(s) to the ``front`` container in ``docker-compose.yml``.
|
||
|
||
.. code-block:: yaml
|
||
|
||
services:
|
||
front:
|
||
labels:
|
||
# Enable TLS
|
||
- "traefik.http.routers.mailu-secure.tls"
|
||
# Your main domain
|
||
- "traefik.http.routers.mailu-secure.tls.domains[0].main=your.example.com"
|
||
# Optional SANs for your main domain
|
||
- "traefik.http.routers.mailu-secure.tls.domains[0].sans=mail.your.example.com,webmail.your.example.com,smtp.your.example.com"
|
||
# Optionally add other domains
|
||
- "traefik.http.routers.mailu-secure.tls.domains[1].main=mail.other.example.com"
|
||
- "traefik.http.routers.mailu-secure.tls.domains[1].sans=mail2.other.example.com,mail3.other.example.com"
|
||
# Your ACME certificate resolver
|
||
- "traefik.http.routers.mailu-secure.tls.certResolver=foo"
|
||
|
||
Of course, be sure to define the Certificate Resolver ``foo`` in the static configuration as well.
|
||
|
||
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`: https://traefik.io/
|
||
|
||
Override Mailu configuration
|
||
----------------------------
|
||
|
||
If you do not have the resources for running a separate reverse proxy, you could override Mailu reverse proxy configuration by using :ref:`an override<override-label>`.
|
||
Simply store your configuration file (Nginx format), in ``/mailu/overrides/nginx.conf``.
|
||
All ``*.conf`` files will be included in the main server block of Mailu in nginx which listens on port 80/443.
|
||
Add location blocks for any services that must be proxied.
|
||
|
||
You can also download the example configuration files:
|
||
|
||
- :download:`compose/traefik/docker-compose.yml`
|
||
- :download:`compose/traefik/traefik.toml`
|
||
|
||
.. _have Mailu Web frontend listen locally and use your own Web frontend on top of it: #have-mailu-web-frontend-listen-locally
|
||
.. _use Traefik in another container as central system-reverse-proxy: #traefik-as-reverse-proxy
|
||
.. _override Mailu Web frontend configuration: #override-mailu-configuration
|
||
|