Billionmail/BillionMail · error
fail to set ssl
Error message
fail to set ssl: %w
What it means
SetSSL wraps any error from crt.SetSNI(public.FormatMX(req.Domain), req.Certificate, req.Key) with this message. SetSNI installs the certificate/key pair as an SNI entry for the mail hostname (mail.example.com) in the mail server config, so failures mean the cert could not be written or applied.
Solutions
- Validate that req.Key is the private key corresponding to req.Certificate (compare modulus/pubkey) and both are valid PEM.
- Ensure the full chain (leaf + intermediates) is included and markers/line endings are intact.
- Inspect the wrapped inner error (%w) for the exact SetSNI failure and fix filesystem/permission issues it reports.
- Restart the mail service if config was partially written, then retry.
Example fix
// before
{"certificate":"-----BEGIN CERTIFICATE-----\nMIIB...", "key":"<ssh key by mistake>"}
// after
{"certificate":"-----BEGIN CERTIFICATE-----\n...CHAIN...\n-----END CERTIFICATE-----", "key":"-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"} Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: match cert and key, and check PEM markers
certPub := extractPubKey(certPEM)
keyPub := extractPubKey(keyPEM)
if !bytes.Equal(certPub, keyPub) {
return errors.New("certificate and private key do not match")
}
if !strings.Contains(certPEM, "BEGIN CERTIFICATE") || !strings.Contains(keyPEM, "BEGIN") {
return errors.New("invalid PEM content")
} Try / catch
if err := setSSL(domain, cert, key); err != nil {
var inner error
errors.As(err, &inner) // message is 'fail to set ssl: %w'; log the unwrapped cause
return fmt.Errorf("SSL install failed: %v", inner)
} Prevention
- Always upload matching cert/key pairs generated together.
- Include the full chain and use BEGIN/END PEM markers with LF line endings.
- Ensure the cert store directory is writable by the service user in your deployment.
When it happens
Trigger: Passing an invalid PEM certificate or mismatched private key in req.Certificate/req.Key; empty cert/key fields; SetSNI failing to update the underlying mail service config; file permission problems writing the cert store.
Common situations: Uploading a cert whose key does not match; cert chain in wrong order; pasting a cert with Windows line endings or missing BEGIN/END markers; container lacking write access to the cert directory; Docker volume not mounted.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- certificate content is empty in database
- certificate not found in database
- Failed to create directory
- failed to parse certificate info
- Failed to save certificate file
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/d0b35cdb7c0e6c66.
Report an issue: GitHub.
Appendix: source
Thrown at core/internal/controller/domains/domains_v1_set_ssl.go:34
if ex, err1 := domains.Exists(ctx, req.Domain); !ex {
if err1 != nil {
res.SetError(fmt.Errorf("fail to check domain: %w", err1))
return
}
res.SetError(fmt.Errorf("domain %s does not exist", req.Domain))
return
}
crt := mail_service.NewCertificate()
defer crt.Close()
err = crt.SetSNI(public.FormatMX(req.Domain), req.Certificate, req.Key)
if err != nil {
res.SetError(fmt.Errorf("fail to set ssl: %w", err))
return
}
_ = public.WriteLog(ctx, public.LogParams{
Type: consts.LOGTYPE.Domain,
Log: "Set SSL for domain :" + req.Domain + " successfully",
Data: req,
})
res.SetSuccess(public.LangCtx(ctx, "Success"))
return
}
View on GitHub (pinned to fc36c76c05)