Tutorial for publishing Mailcow behind Traefik V3 using full TCP passthrough.

Overview Link to heading

In this setup, Traefik only acts as a TCP forwarder. It does not terminate TLS or alter the traffic of the mail services. This is important to keep compatibility with SMTP, SMTPS, IMAP, IMAPS, and Sieve.

Mailcow remains responsible for certificates, internal services, and authentication logic. Traefik only exposes the ports and forwards the connections to the correct backend.

When to use full passthrough Link to heading

Use this model when:

  • you want Mailcow to keep control of the TLS certificates;

  • you need to expose mail services without application-layer inspection;

  • you want to avoid TLS negotiation issues in protocols such as SMTP and IMAP;

  • you want a simple TCP routing layer at the edge.

Prerequisites Link to heading

Before you begin, make sure you already have:

  • Traefik V3 running;

  • Mailcow installed and reachable on the internal network;

  • DNS pointing to the correct public IP;

  • The required ports open in the firewall;

  • An alternate port plan if Traefik is running in LXC.

Edge router port forwarding Link to heading

On the edge router, forward the required external ports to the Traefik host as follows:

  • 80 -> 80
  • 443 -> 443
  • 110 -> 110
  • 143 -> 143
  • 465 -> 465
  • 587 -> 587
  • 993 -> 993
  • 995 -> 995
  • 25 -> 2525

Keep the SMTP inbound exception on 2525 if port 25 is not available directly on the Traefik host, especially in LXC or other constrained environments.

If you run Traefik in Docker, you can publish the SMTP port like this:

1ports:
2  - "2525:25"

This keeps the external SMTP entry on 2525 while forwarding it to container port 25.

Certificate generation with DNS-01 Link to heading

Because ports 80 and 443 are reserved for Traefik on the edge, Mailcow cannot complete the usual HTTP-01 validation path directly on its own host. In this setup, Mailcow must request certificates with DNS-01 instead of HTTP-01.

Follow the Mailcow DNS-01 documentation here: mailcow DNS-01 SSL guide.

The usual flow is:

  1. Enable DNS-01 in mailcow.conf.
  2. Configure the DNS provider credentials in data/conf/acme/dns-01.conf.
  3. Restart the acme-mailcow container.
  4. Verify the certificate request in the logs.

With DNS-01, Mailcow validates ownership through DNS TXT records, so it does not need direct public access to port 80 for certificate issuance.

Traefik static configuration Link to heading

Below is the static configuration with the TCP ports needed for Mailcow:

 1entryPoints:
 2  smtp-in:
 3    address: "[::]:2525"
 4  http:
 5    address: "[::]:80"
 6  pop3:
 7    address: "[::]:110"
 8  imap:
 9    address: "[::]:143"
10  https:
11    address: "[::]:443"
12  smtps:
13    address: "[::]:465"
14  smtp:
15    address: "[::]:587"
16  imaps:
17    address: "[::]:993"
18  pop3s:
19    address: "[::]:995"
20  sieve:
21    address: "[::]:4190"

Traefik dynamic configuration Link to heading

The dynamic configuration below defines the TCP routers and services for Mailcow. For HTTPS certificate passthrough, the mailcow-https router must be a TCP router. A normal HTTP router would terminate TLS at the application layer, which breaks passthrough.

The https entryPoint is used for the Mailcow web interface and certificate passthrough. The http entryPoint can be kept for plain HTTP handling or redirects if you want to add them later.

  1tcp:
  2  routers:
  3    smtp-in:
  4      entryPoints:
  5        - smtp-in
  6      rule: "HostSNI(`*`)"
  7      service: smtp-in
  8      tls:
  9        passthrough: true
 10        domains:
 11          - main: mail.domain.com
 12            sans: []
 13
 14    pop3:
 15      entryPoints:
 16        - pop3
 17      rule: "HostSNI(`*`)"
 18      service: pop3
 19      tls:
 20        passthrough: true
 21        domains:
 22          - main: mail.domain.com
 23            sans: []
 24
 25    imap:
 26      entryPoints:
 27        - imap
 28      rule: "HostSNI(`*`)"
 29      service: imap
 30      tls:
 31        passthrough: true
 32        domains:
 33          - main: mail.domain.com
 34            sans: []
 35
 36    mailcow-https:
 37      entryPoints:
 38        - https
 39      rule: "HostSNI(`mail.domain.com`) || HostSNI(`autoconfig.domain.com`) || HostSNI(`autodiscover.domain.com`)"
 40      service: mailcow-https
 41      tls:
 42        passthrough: true
 43
 44    smtps:
 45      entryPoints:
 46        - smtps
 47      rule: "HostSNI(`*`)"
 48      service: smtps
 49      tls:
 50        passthrough: true
 51        domains:
 52          - main: mail.domain.com
 53            sans: []
 54
 55    smtp:
 56      entryPoints:
 57        - smtp
 58      rule: "HostSNI(`*`)"
 59      service: smtp
 60      tls:
 61        passthrough: true
 62        domains:
 63          - main: mail.domain.com
 64            sans: []  
 65
 66    imaps:
 67      entryPoints:
 68        - imaps
 69      rule: "HostSNI(`*`)"
 70      service: imaps
 71      tls:
 72        passthrough: true
 73        domains:
 74          - main: mail.domain.com
 75            sans: []
 76
 77    pop3s:
 78      entryPoints:
 79        - pop3s
 80      rule: "HostSNI(`*`)"
 81      service: pop3s
 82      tls:
 83        passthrough: true
 84        domains:
 85          - main: mail.domain.com
 86            sans: []
 87
 88    sieve:
 89      entryPoints:
 90        - sieve
 91      rule: "HostSNI(`*`)"
 92      service: sieve
 93      tls:
 94        passthrough: true
 95        domains:
 96          - main: mail.domain.com
 97            sans: []
 98
 99services:
100    smtp-in:
101      loadBalancer:
102        servers:
103          - address: "mailcow-ip:25" 
104
105    pop3:
106      loadBalancer:
107        servers:
108          - address: "mailcow-ip:110"  
109
110    imap:
111      loadBalancer:
112        servers:
113          - address: "mailcow-ip:143"  
114
115    mailcow-https:
116      loadBalancer:
117        servers:
118          - address: "mailcow-ip:443"  
119
120    smtps:
121      loadBalancer:
122        servers:
123          - address: "mailcow-ip:465"  
124
125    smtp:
126      loadBalancer:
127        servers:
128          - address: "mailcow-ip:587"  
129
130    imaps:
131      loadBalancer:
132        servers:
133          - address: "mailcow-ip:993"  
134
135    pop3s:
136      loadBalancer:
137        servers:
138          - address: "mailcow-ip:995"  
139
140    sieve:
141      loadBalancer:
142        servers:
143          - address: "mailcow-ip:4190"

What each port does Link to heading

  • 25: SMTP inbound on Mailcow, reached through the Traefik smtp-in entryPoint.
  • 2525: alternative for inbound SMTP traffic when you do not want to use port 25.
  • 80: HTTP entryPoint on Traefik.
  • 443: HTTPS entryPoint on Traefik.
  • 110: POP3.
  • 995: POP3S.
  • 587: authenticated mail submission.
  • 465: SMTPS.
  • 143: IMAP over plaintext or STARTTLS.
  • 993: IMAPS.
  • 4190: Sieve.

Important note about port 25 Link to heading

If you run Traefik in LXC, it is common to replace port 25 with another port, such as 2525, because of network limitations, NAT, permissions, or a conflict with the host.

In that case, expose inbound SMTP on another port in Traefik and adjust the external forwarding if needed.

Best practices Link to heading

  • Do not terminate TLS in Traefik for these services if the goal is full passthrough.
  • Make sure Mailcow is listening on the correct internal ports.
  • Test each protocol separately: SMTP, SMTPS, IMAP, IMAPS, and Sieve.
  • Verify that the firewall allows the ports exposed by Traefik.
  • In LXC environments, validate port publishing before going to production.

Summary Link to heading

With full passthrough, Traefik V3 works as a TCP transport layer for Mailcow without interfering with the TLS used by the mail services. This simplifies routing and reduces compatibility issues, especially in LXC environments or setups with port restrictions.