1
0
mirror of https://github.com/Mailu/Mailu.git synced 2024-12-16 10:59:53 +02:00
Mailu/docs/reverse.rst
Florent Daigniere b7e7f0d8b6 doc
2023-08-09 15:38:27 +02:00

306 lines
11 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 RESTful API as ``/api``, 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|api|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
------------------------
.. code-block:: yaml
reverse-proxy:
# The official v2 Traefik docker image
image: traefik:v2.10
# Enables the web UI and tells Traefik to listen to docker
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.allowEmptyServices=true"
- "--entrypoints.web.address=:http"
- "--entrypoints.websecure.address=:https"
- "--entrypoints.smtp.address=:smtp"
- "--entrypoints.submission.address=:submission"
- "--entrypoints.submissions.address=:submissions"
- "--entrypoints.imap.address=:imap"
- "--entrypoints.imaps.address=:imaps"
- "--entrypoints.pop3.address=:pop3"
- "--entrypoints.pop3s.address=:pop3s"
- "--entrypoints.sieve.address=:sieve"
# - "--api.insecure=true"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=test@example.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
- "--log.level=DEBUG"
ports:
# The HTTP port
- "25:25"
- "80:80"
- "443:443"
- "465:465"
- "587:587"
- "993:993"
- "995:995"
- "110:110"
- "143:143"
- "4190:4190"
# The Web UI (enabled by --api.insecure=true)
#- "8080:8080"
volumes:
# So that Traefik can listen to the Docker events
- /var/run/docker.sock:/var/run/docker.sock
and then for front:
.. code-block:: yaml
labels:
- "traefik.enable=true"
# the second part is important to ensure Mailu can get certificates for the main FQDN
- "traefik.http.routers.web.rule=Host(`fqdn.example.com`) || Path(`/.well-known/acme-challenge/`)"
- "traefik.http.routers.web.entrypoints=web"
- "traefik.http.services.web.loadbalancer.server.port=80"
# add other FQDNS here too
- "traefik.tcp.routers.websecure.rule=HostSNI(`fqdn.example.com`) || HostSNI(`autoconfig.example.com`) || HostSNI(`mta-sts.example.com`)"
- "traefik.tcp.routers.websecure.entrypoints=websecure"
- "traefik.tcp.routers.websecure.tls.passthrough=true"
- "traefik.tcp.routers.websecure.service=websecure"
- "traefik.tcp.services.websecure.loadbalancer.server.port=443"
- "traefik.tcp.services.websecure.loadbalancer.proxyProtocol.version=2"
- "traefik.tcp.routers.smtp.rule=HostSNI(`*`)"
- "traefik.tcp.routers.smtp.entrypoints=smtp"
- "traefik.tcp.routers.smtp.service=smtp"
- "traefik.tcp.services.smtp.loadbalancer.server.port=25"
- "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.entrypoints=submissions"
- "traefik.tcp.routers.submissions.service=submissions"
- "traefik.tcp.services.submissions.loadbalancer.server.port=465"
- "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.entrypoints=imaps"
- "traefik.tcp.routers.imaps.service=imaps"
- "traefik.tcp.services.imaps.loadbalancer.server.port=993"
- "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.entrypoints=pop3s"
- "traefik.tcp.routers.pop3s.service=pop3s"
- "traefik.tcp.services.pop3s.loadbalancer.server.port=995"
- "traefik.tcp.services.pop3s.loadbalancer.proxyProtocol.version=2"
- "traefik.tcp.routers.sieve.rule=HostSNI(`*`)"
- "traefik.tcp.routers.sieve.entrypoints=sieve"
- "traefik.tcp.routers.sieve.service=sieve"
- "traefik.tcp.services.sieve.loadbalancer.server.port=4190"
- "traefik.tcp.services.sieve.loadbalancer.proxyProtocol.version=2"
healthcheck:
test: ['NONE']
in mailu.env:
.. code-block:: docker
#mailu.env file
REAL_IP_FROM=192.168.203.0/24
PROXY_PROTOCOL=all-but-http
TRAEFIK_VERSION=v2
TLS_FLAVOR=mail-letsencrypt
WEBROOT_REDIRECT=/sso/login
.. _`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