Skip to main content

Traefik

Traefik is a modern, dynamic reverse proxy and load balancer designed to deploy microservices with ease. It integrates seamlessly with major container orchestrators like Docker, Kubernetes, and others, automatically discovering the services and adjusting configurations accordingly. Traefik's dynamic nature, extensive integration capabilities, and robust feature set make it an ideal choice for managing and routing traffic to microservice applications.

Stalwart Mail Server supports Traefik, allowing you to take advantage of Traefik's capabilities to manage and route traffic efficiently to your email server. By using Traefik as a reverse proxy, you can ensure high availability, scalability, and security for your Stalwart Mail Server. Additionally, Traefik’s support for the Proxy Protocol further enhances Stalwart’s ability to perform sender authentication and enforce security policies effectively.

Configuration

The following example demonstrates how to configure Traefik to use the Proxy Protocol with Stalwart Mail Server:

Traefik Compose

services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: always
networks:
proxy:
ipv4_address: 172.19.0.2
ports:
- 80:80
- 443:443
- 25:25
- 465:465
- 993:993
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/traefik:/etc/traefik
- acme:/etc/certs
- /var/run/docker.sock:/var/run/docker.sock:ro

traefik-certs-dumper:
image: ghcr.io/kereis/traefik-certs-dumper:latest
container_name: traefik-certs-dumper
restart: unless-stopped
depends_on:
- traefik
volumes:
- /etc/localtime:/etc/localtime:ro
- acme:/traefik:ro
- certs:/output


volumes:
acme:
certs:

networks:
proxy:

Stalwart Compose

services:
mailserver:
image: stalwartlabs/mail-server:latest
container_name: mailserver
restart: unless-stopped
hostname: mail.example.com
networks:
proxy:
ipv4_address: 172.19.0.5
volumes:
- /etc/localtime:/etc/localtime:ro
- data:/opt/stalwart-mail
- certs:/data/certs:ro
labels:
- traefik.enable=true

- traefik.http.routers.mailserver.rule=Host(`mail.example.com`) || Host(`autodiscover.example.com`) || Host(`autoconfig.example.com`) || Host(`mta-sts.example.com`)
- traefik.http.routers.mailserver.entrypoints=https
- traefik.http.routers.mailserver.service=mailserver
- traefik.http.services.mailserver.loadbalancer.server.port=8080

- 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.jmap.rule=HostSNI(`*`)
- traefik.tcp.routers.jmap.tls.passthrough=true
- traefik.tcp.routers.jmap.entrypoints=https
- traefik.tcp.routers.jmap.service=jmap
- traefik.tcp.services.jmap.loadbalancer.server.port=443
- traefik.tcp.services.jmap.loadbalancer.proxyProtocol.version=2

- traefik.tcp.routers.smtps.rule=HostSNI(`*`)
- traefik.tcp.routers.smtps.tls.passthrough=true
- traefik.tcp.routers.smtps.entrypoints=smtps
- traefik.tcp.routers.smtps.service=smtps
- traefik.tcp.services.smtps.loadbalancer.server.port=465
- traefik.tcp.services.smtps.loadbalancer.proxyProtocol.version=2

- traefik.tcp.routers.imaps.rule=HostSNI(`*`)
- traefik.tcp.routers.imaps.tls.passthrough=true
- 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

volumes:
data:
certs:
name: traefik_certs
external: true

networks:
proxy:
name: traefik_proxy
external: true

Traefik Configuration

The configuration example below obtains Let's Encrypt certificates using the DNS challenge on Cloudflare and enables the Proxy Protocol for the SMTP, SMTPS, and IMAPS entry points:

global:
checkNewVersion: true
sendAnonymousUsage: false

certificatesResolvers:
letsencrypt:
acme:
keyType: EC256
dnsChallenge:
provider: cloudflare
email: REDACTED
storage: /etc/certs/acme.json

entryPoints:
http:
address: :80
http3: {}
http:
redirections:
entryPoint:
to: https
scheme: https

https:
address: :443
http3: {}
http:
tls:
certResolver: letsencrypt

smtp:
address: :25
proxyProtocol:
trustedIPs:
- 172.19.0.2
- 172.19.0.5

smtps:
address: :465
proxyProtocol:
trustedIPs:
- 172.19.0.2
- 172.19.0.5

imaps:
address: :993
proxyProtocol:
trustedIPs:
- 172.19.0.2
- 172.19.0.5

tls:
options:
default:
minVersion: VersionTLS12

providers:
docker:
exposedByDefault: false

Stalwart configuration

In the example below the proxy protocol is enabled on all mail ports except for the HTTP port:

certificate.default.cert = "%{file:/data/certs/mail.example.com/cert.pem}%"
certificate.default.default = true
certificate.default.private-key = "%{file:/data/certs/mail.example.com/key.pem}%"
lookup.default.hostname = "mail.example.com"
server.http.hsts = true
server.http.permissive-cors = false
server.http.url = "protocol + '://' + key_get('default', 'hostname') + ':' + local_port"
server.http.use-x-forwarded = true
server.listener.http.bind = "[::]:8080"
server.listener.http.protocol = "http"
server.listener.https.bind = "[::]:443"
server.listener.https.protocol = "http"
server.listener.https.tls.implicit = true
server.listener.imaptls.bind = "[::]:993"
server.listener.imaptls.protocol = "imap"
server.listener.imaptls.proxy.override = true
server.listener.imaptls.proxy.trusted-networks.0 = "172.19.0.2"
server.listener.imaptls.proxy.trusted-networks.1 = "172.19.0.0/16"
server.listener.imaptls.tls.implicit = true
server.listener.smtp.bind = "[::]:25"
server.listener.smtp.protocol = "smtp"
server.listener.smtp.proxy.override = true
server.listener.smtp.proxy.trusted-networks.0 = "172.19.0.2"
server.listener.smtp.proxy.trusted-networks.1 = "172.19.0.0/16"
server.listener.submissions.bind = "[::]:465"
server.listener.submissions.protocol = "smtp"
server.listener.submissions.proxy.override = true
server.listener.submissions.proxy.trusted-networks.0 = "172.19.0.2"
server.listener.submissions.proxy.trusted-networks.1 = "172.19.0.0/16"
server.listener.submissions.tls.implicit = true