How to Fix DANE / TLSA Verification Errors for Mail Servers on Virtualmin with Let’s Encrypt

If you are running a mail server using Virtualmin / Webmin and testing your domain on security checkers like Internet.nl, you might encounter issues with DANE (DNS-based Authentication of Named Entities) validation.

In this guide, we’ll walk through how we diagnosed a failing DANE setup, converted Let’s Encrypt certificates to the modern Elliptic Curve (EC) format, and configured Virtualmin to automatically manage TLSA records so renewals never break DANE again.

The Problem: DANE Mismatch on Port 25

When testing a mail server’s security configuration, Internet.nl checks whether the TLSA records in your DNS match the actual SSL/TLS certificate served by your SMTP service (Postfix on port 25).

Common issues include:

  • Selector Mismatch: DNS publishing a 3 1 1 record (Selector 1 = SubjectPublicKeyInfo / Public Key), while the mail server serves a certificate whose hash doesn’t match the record.
  • Certificate Type Mismatch: The TLSA record being configured for an RSA key while the certificate was re-issued as Elliptic Curve (ECDSA), or vice versa.
  • Stale Hashes After Certificate Renewal: Let’s Encrypt certificates renew every 60–90 days. If the TLSA record in DNS isn’t updated alongside the certificate, DANE verification fails immediately.

Step 1: Checking Your Current Certificate & Key Type

First, determine what key type and hash your mail server is currently using for TLS on port 25. You can test this using openssl:

Bash

# Connect to SMTP with STARTTLS and extract the certificate fingerprint (SHA-256)
openssl s_client -connect mail.example.com:25 -starttls smtp -showcerts < /dev/null 2>/dev/null | openssl x509 -outform DER | openssl dgst -sha256

Compare the output hash against what is stored in your DNS TLSA record:

Bash

# Query the TLSA record for port 25 (SMTP)
dig +short TLSA _25._tcp.mail.example.com

An example output of a TLSA record:

Plaintext

3 0 1 A1B2C3D4E5F67890123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0

Understanding TLSA Parameters:

  • Usage (3): DANE-EE — Binds directly to the end-entity certificate.
  • Selector (0 or 1):
    • 0 = Full Certificate
    • 1 = SubjectPublicKeyInfo (Public Key only)
  • Matching Type (1): SHA-256 hash.

Step 2: Requesting an ECDSA (Elliptic Curve) Certificate in Virtualmin

Modern DANE setups strongly recommend using ECDSA (Elliptic Curve) certificates (such as P-256 / prime256v1) instead of legacy RSA keys, as they offer better performance and smaller cryptographic signatures.

To request/re-issue an EC certificate via Virtualmin:

  1. Log in to Virtualmin and select your domain (example.com).
  2. Go to Server Configuration $\rightarrow$ SSL Certificate.
  3. Click on the Let’s Encrypt tab.
  4. Under Key size / type, select Elliptic Curve (ECDSA) or specify the EC curve P-256.
  5. Click Request Certificate.

Once issued, apply the certificate to your mail service:

  • Click Copy to Postfix (and Copy to Dovecot if applicable) so your mail server uses the new EC certificate.

Step 3: Generating and Verifying the TLSA Hash

If you want to verify or manually insert the TLSA record, generate the exact SHA-256 fingerprint from your live certificate:

For 3 0 1 (Full Certificate Hash):

Bash

openssl x509 -in /etc/ssl/virtualmin/1234567890/ssl.cert -outform DER | openssl dgst -sha256

For 3 1 1 (Public Key Hash):

Bash

openssl x509 -in /etc/ssl/virtualmin/1234567890/ssl.cert -pubkey -noout | openssl pkey -pubin -outform DER | openssl dgst -sha256

Add the resulting hash into your DNS zone as a TLSA record under host _25._tcp.mail.example.com.

Step 4: Automating TLSA Record Updates in Virtualmin

To prevent DANE validation from breaking every time Let’s Encrypt automatically renews your certificate, you must ensure Virtualmin automatically updates the TLSA record in BIND DNS upon renewal.

  1. In Virtualmin, navigate to DNS Settings $\rightarrow$ DNS Options.
  2. Locate the option TLSA records enabled.
  3. Set TLSA records enabled to Yes.
  4. Click Save at the bottom of the page.
       ┌──────────────────────────────────────────────┐
       │ DNS Options                                  │
       ├──────────────────────────────────────────────┤
       │ TLSA records enabled : [X] Yes  [ ] No       │
       └──────────────────────────────────────────────┘

How this automation works:

  • Every time Virtualmin / Certbot renews the Let’s Encrypt certificate, Virtualmin re-calculates the TLSA hash.
  • It updates the _25._tcp TLSA record in your local BIND DNS zone file.
  • If DNSSEC is enabled on your Virtualmin server, it automatically re-signs the DNS zone.

Step 5: Testing Your Setup

After applying the changes and allowing DNS propagation (ensure your TTL is set low, e.g., 3600 seconds):

  1. Re-run the domain test at Internet.nl.
  2. Verify that:
    • DNSSEC passes.
    • DANE for SMTP (Port 25) shows a green checkmark.
    • Both STARTTLS and certificate validation are fully compliant.

Key Takeaways

  • Match Your Selectors: Ensure your DNS TLSA record selector (0 for Full Cert, 1 for Public Key) matches the hash you generate.
  • Keep TTLs Low: Keep TLSA record TTLs short (e.g., 1 hour) so cached records expire quickly when certificates renew.
  • Enable Automation: Always let Virtualmin handle TLSA generation (TLSA records enabled = Yes) if Virtualmin manages your authoritative DNS zone.