mirror of
https://github.com/Mailu/Mailu.git
synced 2024-12-12 10:45:38 +02:00
Merge pull request #724 from Nebukadneza/traefik_support
Documentation and examples for traefik
This commit is contained in:
commit
7eff09a74b
143
docs/compose/traefik/docker-compose.yml
Normal file
143
docs/compose/traefik/docker-compose.yml
Normal file
@ -0,0 +1,143 @@
|
||||
version: '2'
|
||||
|
||||
services:
|
||||
|
||||
# This would normally not be here, but where you define your system services
|
||||
traefik:
|
||||
image: traefik:alpine
|
||||
command: --docker
|
||||
restart: always
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock"
|
||||
- "/data/traefik/acme.json:/acme.json"
|
||||
- "/data/traefik/traefik.toml:/traefik.toml"
|
||||
# This may be needed (plus defining mailu_default external: true) if traefik lives elsewhere
|
||||
# networks:
|
||||
# - mailu_default
|
||||
|
||||
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:
|
||||
- "/data/traefik:/traefik"
|
||||
- "$ROOT/certs:/output"
|
||||
|
||||
front:
|
||||
image: mailu/nginx:$VERSION
|
||||
restart: always
|
||||
env_file: .env
|
||||
logging:
|
||||
driver: $LOG_DRIVER
|
||||
labels: # Traefik labels for simple reverse-proxying
|
||||
- "traefik.enable=true"
|
||||
- "traefik.port=80"
|
||||
- "traefik.frontend.rule=Host:$TRAEFIK_DOMAIN"
|
||||
- "traefik.docker.network=mailu_default"
|
||||
ports:
|
||||
- "$BIND_ADDRESS4:110:110"
|
||||
- "$BIND_ADDRESS4:143:143"
|
||||
- "$BIND_ADDRESS4:993:993"
|
||||
- "$BIND_ADDRESS4:995:995"
|
||||
- "$BIND_ADDRESS4:25:25"
|
||||
- "$BIND_ADDRESS4:465:465"
|
||||
- "$BIND_ADDRESS4:587:587"
|
||||
- "$BIND_ADDRESS6:110:110"
|
||||
- "$BIND_ADDRESS6:143:143"
|
||||
- "$BIND_ADDRESS6:993:993"
|
||||
- "$BIND_ADDRESS6:995:995"
|
||||
- "$BIND_ADDRESS6:25:25"
|
||||
- "$BIND_ADDRESS6:465:465"
|
||||
- "$BIND_ADDRESS6:587:587"
|
||||
volumes:
|
||||
- "$ROOT/overrides/nginx:/overrides"
|
||||
- /data/traefik/ssl/$TRAEFIK_DOMAIN.crt:/certs/cert.pem
|
||||
- /data/traefik/ssl/$TRAEFIK_DOMAIN.key:/certs/key.pem
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
restart: always
|
||||
volumes:
|
||||
- "$ROOT/redis:/data"
|
||||
|
||||
imap:
|
||||
image: mailu/dovecot:$VERSION
|
||||
restart: always
|
||||
env_file: .env
|
||||
volumes:
|
||||
- "$ROOT/mail:/mail"
|
||||
- "$ROOT/overrides:/overrides"
|
||||
depends_on:
|
||||
- front
|
||||
|
||||
smtp:
|
||||
image: mailu/postfix:$VERSION
|
||||
restart: always
|
||||
env_file: .env
|
||||
volumes:
|
||||
- "$ROOT/overrides:/overrides"
|
||||
depends_on:
|
||||
- front
|
||||
|
||||
antispam:
|
||||
image: mailu/rspamd:$VERSION
|
||||
restart: always
|
||||
env_file: .env
|
||||
volumes:
|
||||
- "$ROOT/filter:/var/lib/rspamd"
|
||||
- "$ROOT/dkim:/dkim"
|
||||
- "$ROOT/overrides/rspamd:/etc/rspamd/override.d"
|
||||
depends_on:
|
||||
- front
|
||||
|
||||
antivirus:
|
||||
image: mailu/$ANTIVIRUS:$VERSION
|
||||
restart: always
|
||||
env_file: .env
|
||||
volumes:
|
||||
- "$ROOT/filter:/data"
|
||||
|
||||
webdav:
|
||||
image: mailu/$WEBDAV:$VERSION
|
||||
restart: always
|
||||
env_file: .env
|
||||
volumes:
|
||||
- "$ROOT/dav:/data"
|
||||
|
||||
admin:
|
||||
image: mailu/admin:$VERSION
|
||||
restart: always
|
||||
env_file: .env
|
||||
volumes:
|
||||
- "$ROOT/data:/data"
|
||||
- "$ROOT/dkim:/dkim"
|
||||
depends_on:
|
||||
- redis
|
||||
|
||||
webmail:
|
||||
image: "mailu/$WEBMAIL:$VERSION"
|
||||
restart: always
|
||||
env_file: .env
|
||||
volumes:
|
||||
- "$ROOT/webmail:/data"
|
||||
depends_on:
|
||||
- imap
|
||||
|
||||
fetchmail:
|
||||
image: mailu/fetchmail:$VERSION
|
||||
restart: always
|
||||
env_file: .env
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: $SUBNET
|
33
docs/compose/traefik/traefik.toml
Normal file
33
docs/compose/traefik/traefik.toml
Normal file
@ -0,0 +1,33 @@
|
||||
# This is just boilerplate stuff you probably have in your own config
|
||||
logLevel = "INFO"
|
||||
defaultEntryPoints = ["https","http"]
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.http.redirect]
|
||||
entryPoint = "https"
|
||||
[entryPoints.https]
|
||||
address = ":443"
|
||||
[entryPoints.https.tls]
|
||||
|
||||
[docker]
|
||||
endpoint = "unix:///var/run/docker.sock"
|
||||
watch = true
|
||||
exposedByDefault = false
|
||||
|
||||
# Make sure we get acme.json saved, and onHostRule enabled
|
||||
[acme]
|
||||
email = "your@mail.tld"
|
||||
storage = "acme.json"
|
||||
entryPoint = "https"
|
||||
onHostRule = true
|
||||
|
||||
[acme.httpChallenge]
|
||||
entryPoint = "http"
|
||||
|
||||
# This should include all of your mail domains, and main= should be your $TRAEFIK_DOMAIN
|
||||
[[acme.domains]]
|
||||
main = "mail.your.doma.in"
|
||||
sans = ["web.mail.your.doma.in", "smtp.mail.doma.in", "imap.mail.doma.in"]
|
||||
|
@ -8,6 +8,7 @@ In such a configuration, one would usually run a frontend reverse proxy to serve
|
||||
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
|
||||
- disable Mailu Web frontend completely and use your own
|
||||
|
||||
@ -114,11 +115,87 @@ Depending on how you access the front server, you might want to add a ``proxy_re
|
||||
|
||||
This will stop redirects (301 and 302) sent by the Webmail, nginx front and admin interface from sending you to ``localhost``.
|
||||
|
||||
Use Traefik in another container as central system-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 ``…:440``.
|
||||
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.doma.in`` now. However,
|
||||
``mail.your.doma.in`` might only be the location where you want the Mailu web-interfaces to live — your mail should be sent/received from ``your.doma.in``,
|
||||
and this is the ``DOMAIN`` in your ``.env``?
|
||||
To support that use-case, Traefik can request ``SANs`` for your domain. Lets add something like
|
||||
|
||||
.. code-block:: guess
|
||||
|
||||
[acme]
|
||||
[[acme.domains]]
|
||||
main = "your.doma.in" # this is the same as $TRAEFIK_DOMAIN!
|
||||
sans = ["mail.your.doma.in", "webmail.your.doma.in", "smtp.your.doma.in"]
|
||||
|
||||
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:
|
||||
- "/data/traefik:/traefik"
|
||||
- "$ROOT/certs:/output"
|
||||
|
||||
|
||||
|
||||
Assuming you have ``volume-mounted`` your ``acme.json`` put to ``/data/traefik`` on your host. The dumper will then write out ``/data/traefik/ssl/your.doma.in.crt``
|
||||
and ``/data/traefik/ssl/your.doma.in.key`` whenever ``acme.json`` is updated. Yay! Now let’s mount this to our ``front`` container like:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
volumes:
|
||||
- "$ROOT/overrides/nginx:/overrides"
|
||||
- /data/traefik/ssl/$TRAEFIK_DOMAIN.crt:/certs/cert.pem
|
||||
- /data/traefik/ssl/$TRAEFIK_DOMAIN.key:/certs/key.pem
|
||||
|
||||
.. _`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 a Docker volume. Simply store your configuration file (Nginx format), in ``/mailu/nginx.conf`` for instance.
|
||||
If you do not have the resources for running a separate reverse proxy, you could override Mailu reverse proxy configuration by using a Docker volume.
|
||||
Simply store your configuration file (Nginx format), in ``/mailu/nginx.conf`` for instance.
|
||||
|
||||
Then modify your ``docker-compose.yml`` file and change the ``front`` section to add a mount:
|
||||
|
||||
@ -135,7 +212,10 @@ Then modify your ``docker-compose.yml`` file and change the ``front`` section to
|
||||
- "$ROOT/certs:/certs"
|
||||
- "$ROOT/nginx.conf:/etc/nginx/nginx.conf"
|
||||
|
||||
You can use our default configuration file as a sane base for your configuration.
|
||||
You can also download the example configuration files:
|
||||
|
||||
- :download:`compose/traefik/docker-compose.yml`
|
||||
- :download:`compose/traefik/traefik.toml`
|
||||
|
||||
Disable completely Mailu reverse proxy
|
||||
--------------------------------------
|
||||
|
2
optional/traefik-certdumper/.dockerignore
Normal file
2
optional/traefik-certdumper/.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
README.md
|
||||
Dockerfile
|
11
optional/traefik-certdumper/Dockerfile
Normal file
11
optional/traefik-certdumper/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
||||
FROM alpine:3.8
|
||||
|
||||
RUN apk --no-cache add inotify-tools jq openssl util-linux bash docker
|
||||
# while not strictly documented, this script seems to always(?) support previous acme.json versions too
|
||||
RUN wget https://raw.githubusercontent.com/containous/traefik/master/contrib/scripts/dumpcerts.sh -O dumpcerts.sh
|
||||
|
||||
VOLUME ["/traefik"]
|
||||
VOLUME ["/output"]
|
||||
|
||||
COPY run.sh /
|
||||
ENTRYPOINT ["/run.sh"]
|
21
optional/traefik-certdumper/LICENSE
Normal file
21
optional/traefik-certdumper/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Sven Dowideit
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
27
optional/traefik-certdumper/README.md
Normal file
27
optional/traefik-certdumper/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Single-domain traefik-certdumper for mailu
|
||||
|
||||
This is based on the work by Sven Dowideit on https://github.com/SvenDowideit/traefik-certdumper
|
||||
|
||||
## Fork?
|
||||
This is a slight modification that is less flexible, but is adapted to the
|
||||
usecase in mailu. If you wish to deploy mailu behind a traefik, you face many
|
||||
problems. One of these is that you need to get the certificates into mailu in a
|
||||
very defined manner. This will copy the certificate for the **Main:**-domain
|
||||
given in the DOMAIN-environment onto `output`.
|
||||
|
||||
If your output happens to be mailu-front-`/certs`, the certificate-watcher in
|
||||
the front-container will catch it and reload nginx. This works for mailu
|
||||
`TLS_FLAVOR=[mail, cert]`
|
||||
|
||||
|
||||
```
|
||||
certdumper:
|
||||
restart: always
|
||||
image: Mailu/traefik-certdumper:$VERSION
|
||||
environment:
|
||||
- DOMAIN=$DOMAIN
|
||||
volumes:
|
||||
# your traefik data-volume is probably declared outside of the mailu composefile
|
||||
- /data/traefik:/traefik
|
||||
- $ROOT/certs/:/output/
|
||||
```
|
30
optional/traefik-certdumper/run.sh
Executable file
30
optional/traefik-certdumper/run.sh
Executable file
@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
|
||||
function dump() {
|
||||
echo "$(date) Dumping certificates"
|
||||
bash dumpcerts.sh /traefik/acme.json /tmp/work/ || return
|
||||
|
||||
for crt_file in $(ls /tmp/work/certs/*); do
|
||||
pem_file=$(echo $crt_file | sed 's/certs/pem/g' | sed 's/.crt/-public.pem/g')
|
||||
echo "openssl x509 -inform PEM -in $crt_file > $pem_file"
|
||||
openssl x509 -inform PEM -in $crt_file > $pem_file
|
||||
done
|
||||
for key_file in $(ls /tmp/work/private/*); do
|
||||
pem_file=$(echo $key_file | sed 's/private/pem/g' | sed 's/.key/-private.pem/g')
|
||||
echo "openssl rsa -in $key_file -text > $pem_file"
|
||||
openssl rsa -in $key_file -text > $pem_file
|
||||
done
|
||||
|
||||
echo "$(date) Copying certificates"
|
||||
cp -v /tmp/work/pem/${DOMAIN}-private.pem /output/key.pem
|
||||
cp -v /tmp/work/pem/${DOMAIN}-public.pem /output/cert.pem
|
||||
}
|
||||
|
||||
mkdir -p /tmp/work/pem /tmp/work/certs
|
||||
# run once on start to make sure we have any old certs
|
||||
dump
|
||||
|
||||
while true; do
|
||||
inotifywait -e modify /traefik/acme.json && \
|
||||
dump
|
||||
done
|
@ -30,6 +30,10 @@ services:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}radicale:${MAILU_VERSION:-local}
|
||||
build: ../optional/radicale
|
||||
|
||||
traefik-certdumper:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}traefik-certdumper:${MAILU_VERSION:-local}
|
||||
build: ../optional/traefik-certdumper
|
||||
|
||||
admin:
|
||||
image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX}admin:${MAILU_VERSION:-local}
|
||||
build: ../core/admin
|
||||
|
Loading…
Reference in New Issue
Block a user