All of the information necessary to get mailcow functioning properly behind traefik 2.x already exists on the web, but I found it somewhat challenging to find all the relevant info in one place.
So first off, traefik. Lets setup a reasonably straightforward traefik instance that'll allow lots of services, and many domains, to run behind it...
Create directory, /opt/traefik
and within it create ad directory data
where we'll store our traefik.yml and acme.json. On that note, touch data/acme.json
and very importantly chmod 600 data/acme.json
... that last point was a huge head scratcher when suddenly my cert resolver stopped working while I was trying to get wildcard certs setup. If the permissions on that file are less strict, traefik will throw out any resolvers associated with that for storage – but then in logs doesn't mention that, just says "resolver foo does not exist" or whatever. Frustrating.
Ok.. so we've got our /opt/traefik
with a data
directory that contains an empty acme.json
file with appropriate permissions.
Now lets add a traefik.yml
file in that data directory too with the following content:
api:
dashboard: true
entryPoints:
http:
address: ":80"
https:
address: ":443"
tls:
options:
default:
sniStrict: true
minVersion: VersionTLS12
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
certificatesResolvers:
default:
acme:
email: you@example.com
storage: acme.json
tlsChallenge: {}
dnsChallenge:
provider: digitalocean
delayBeforeCheck: 0
httpChallenge:
entryPoint: http
Obviously change the email, and dnschallenge provider should be changed or omit as your situation dictates. I don't know for sure if having all three challenge types in there is correct, I imagine if one fails it'll try the next, etc.. but I don't know for certain. In any case its' working for me, including wildcard cert generation.
Next create the docker-compose.yml
file in your /opt/traefik
directory with the following contents:
version: '3'
services:
traefik:
image: traefik:2.2
container_name: traefik
restart: always
security_opt:
- no-new-privileges:true
networks:
- proxy
ports:
- 80:80
- 443:443
environment:
- DO_AUTH_TOKEN=YOUR_DIGITALOCEAN_TOKEN
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme.json:/acme.json
labels:
- traefik.enable=true
- traefik.http.middlewares.traefik-auth.basicauth.users=USER:HASH
- traefik.http.routers.traefik-secure.service=api@internal
- traefik.http.routers.traefik-secure.entrypoints=https
- traefik.http.routers.traefik-secure.rule=Host(`traefik.example.com`)
- traefik.http.routers.traefik-secure.middlewares=traefik-auth
- traefik.http.routers.traefik-secure.tls=true
- traefik.http.routers.traefik-secure.tls.certResolver=default
# Omit next two lines to not do wildcard certs:
- traefik.http.routers.traefik-secure.tls.domains[0].main=example.com
- traefik.http.routers.traefik-secure.tls.domains[0].sans=*.example.com
# Global Redirect to https
- traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)
- traefik.http.routers.http-catchall.entrypoints=http
- traefik.http.routers.http-catchall.middlewares=redirect-to-https
- traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https
networks:
proxy:
external: true
Now since our proxy network is external we'll need to manually create it:
docker network create web
Lets get your basic auth user & password setup too:
Use the hash output from that and replace USER:HASH
in the `docker-compose.yml` file with the username you used, and the output hash.
All that's left to do for this part is fire that bad boy up:
Assuming you had docker, docker-compose, etc installed and your dns is setup, you should now be able to access traefik at traefik.yourdomain.com, and if you hit the http
version it should automagically redirect to https
... that global redirect to https section of our docker-compose config is pretty magical, it catches any http traffic to any host and redirects to https, automatically.
Mailcow
Follow all the steps for getting mailcow up and running from their documentation.
When editing the mailcow.conf file, be sure to set the following, since traefik will proxy the web connections, and handle cert generation:
HTTP_PORT=8080
HTTP_BIND=127.0.0.1
HTTPS_PORT=8443
HTTPS_BIND=127.0.0.1
SKIP_LETS_ENCRYPT=y
Before you start it though, add a new file, docker-compose.override.yml
to the install directory /opt/mailcow_dockerized
with the following content:
version: '2.1'
services:
nginx-mailcow:
expose:
- 8080
labels:
- traefik.enable=true
- traefik.http.routers.nginx-mailcow.rule=HostRegexp(`{host:(autodiscover|autoconfig|webmail|mail|email).+}`)
- traefik.http.routers.nginx-mailcow.entrypoints=https
- traefik.http.routers.nginx-mailcow.rule=Host(`${MAILCOW_HOSTNAME}`)
- traefik.http.routers.nginx-mailcow.tls=true
- traefik.http.routers.nginx-mailcow.tls.certresolver=default
# Uncomment to use wildcard cert:
# - traefik.http.routers.nginx-mailcow.tls.domains[0].main=example.com
# - traefik.http.routers.nginx-mailcow.tls.domains[0].sans=*.example.com
- traefik.http.routers.nginx-mailcow.service=nginx-mailcow
- traefik.http.services.nginx-mailcow.loadbalancer.server.port=8080
- traefik.docker.network=proxy
networks:
- proxy
certdumper:
image: humenius/traefik-certs-dumper
network_mode: none
command: --restart-containers mailcow_postfix-mailcow_1,mailcow_dovecot-mailcow_1,mailcow_nginx-mailcow_1
volumes:
- /opt/traefik/data:/traefik:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/assets/ssl:/output:rw
environment:
- DOMAIN=${MAILCOW_HOSTNAME}
# If using wildcard certs instead of an explicit host cert,
# use following line instead with just the TLD so certdumper
# is able to find the cert.
# - DOMAIN=YourDomain.com
networks:
proxy:
external: true
That should be it. This will get the mailcow web UI running behind traefik using either the FQDN for its cert, or wildcards.. note; if it's the same domain as traefik and traefik already has wildcard certs, you must use the domain name option instead of ${MAILCOW_HOSTNAME} for the domain env setting for cert dumper or it won't be able to find the cert, and if the same domain, you can omit the wildcard cert labels on nginx because that wildcard cert would already be generated by traefik anyway...
Ok, fire that puppy up:
That should get you up and running with mailcow proxied behind traefik. All the mail ports are open directly, but web traffic gets proxied.
If something isn't working, you probably missed a step here, omit a quote or something.. or you have other issues that are related to mailcow – likely dns config or firewall issues. That's all beyond the scope of this post.