Clarification question regarding TLS certificates

Your question

The hostname of my stalwart server is mail.mydomain-a.com. For this, I pass the tls certificate, obtained from caddy, to stalwart. Besides mydomain-a.com, I have some more domains like mydomain-b.com and mydomain-c.com, so that a user can receive mails sent to those domains. Am I correct that I do not need to use a tls certificate for these additional domains? Because everything goes via mail.mydomain-a.com, like email clients connecting to this host, and all mx entries refer to this host?

(I’m not quite sure why stalwart even has to know the above mentioned certificate, since caddy as reverse proxy is supposed to handle it?)

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

Your understanding is essentially correct. Here is a breakdown of both questions:

Do you need TLS certificates for the additional domains (mydomain-b.com, mydomain-c.com)?

No. The certificate only needs to match the hostname that clients actually connect to via TLS – in your case mail.mydomain-a.com. The other domains (mydomain-b.com, mydomain-c.com) are just mail domains: they have MX records pointing at mail.mydomain-a.com, and no client ever opens a TLS connection directly to those domain names. Stalwart selects the certificate to present based on the SNI value the connecting client sends, which will always be mail.mydomain-a.com in your setup. You only need a cert covering that hostname.

Why does Stalwart need the certificate at all if Caddy is the reverse proxy?

Caddy can only act as a reverse proxy for HTTP/HTTPS traffic. The mail protocols – SMTP (port 25/465), IMAP (port 993), POP3, ManageSieve – are raw TCP, not HTTP, so Caddy cannot terminate TLS on those ports unless you use the caddy-l4 plugin. In the typical setup without that plugin, Stalwart itself terminates TLS on the mail ports and therefore needs the certificate. Even with caddy-l4 forwarding those ports, if it’s passing through (not terminating), Stalwart still does the TLS handshake. The docs describe this clearly: “Caddy does not natively forward raw TCP streams, so it cannot forward the mail ports (SMTP, IMAP, POP3, ManageSieve).”

In short: one certificate for mail.mydomain-a.com is all you need, and Stalwart needs it because it handles TLS for the mail protocols directly.

Relevant docs: Caddy reverse proxy | TLS overview

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong. If you found it useful, mention @helpbot in any reply to ask follow-up questions and the bot will respond again.

Thanks, dear helpbot. :blush:

@helpbot, I have a similar setup (caddy only proxies https traffic (admin, DAV)), imaps and submission are handled directly by stalwart) and I have recently upgraded to 0.16. TLS certificate expired and after restart _disappeared_ from stalwart - they are no longer updated through ACME and I have trouble figuring out how to achieve this.

In other words, stalwart reports: 2026-06-12T08:37:42Z WARN No TLS certificates available (tls.no-certificates-available) total = 0

I have ACME provider configured with TLS-ALPN-01 but I can’t see where I can configure that Stalwart should obtain the certificate for the domain automatically? I noticed in the documentation that stalwart should be receiving TCP 443 traffic (which is not the case, since caddy terminates 443) so this might be the reason certs are not obtained? So I changed it to HTTP-01…

When I restart the server, I can see it tries to obtain the certificates from the log file:

2026-06-12T08:52:18Z INFO ACME authentication started (acme.auth-start) hostname = "mta-sts.domain.tld", type = "http-01", url = "https://acme-v02.api.letsencrypt.org/acme/new-order"
2026-06-12T08:52:18Z INFO ACME authentication started (acme.auth-start) hostname = "autoconfig.domain.tld", type = "http-01", url = "https://acme-v02.api.letsencrypt.org/acme/new-order"
2026-06-12T08:52:18Z INFO ACME authentication started (acme.auth-start) hostname = "autodiscover.domain.tld", type = "http-01", url = "https://acme-v02.api.letsencrypt.org/acme/new-order"
2026-06-12T08:52:18Z INFO ACME authentication started (acme.auth-start) hostname = "ua-auto-config.domain.tld", type = "http-01", url = "https://acme-v02.api.letsencrypt.org/acme/new-order"
2026-06-12T08:52:43Z WARN No TLS certificates available (tls.no-certificates-available) total = 0

But nothing is obtained. The reverse proxy logs shows that connection is made to http ./well-known endpoint, redirected to SSL and then requested over SSL successfully.

Related discussion: TLS certs not available - #4 by helpbot

In other words: when using HTTP-01 challenge, it seems that ./well-know is accessed successfully (but maybe caddy serves it instead of stalwart?). The end result being that stalwart does not have any certificates and uses self signed cert for mail.domain.tld.

when using TLS-ALPN-01, no request is seen in reverse proxy and still no certificate.

Not sure how this was working prior to 0.16. I am using 0.16.8 currently.

For the time being, I just copied the ceritiface from caddy to /etc/stalwart/cert/mail.domain.tld.pem and configured a manual certificate.

I think that there must be a better way for a simple docker container setup behind a reverse proxy.

Maybe persistent DNS ACME config?