[Untested] Fully automated SSL setup for mail.* and webmail.* domains

Discussion in 'Developers' Forum' started by ezflashback, Mar 18, 2026 at 2:19 PM.

  1. ezflashback

    ezflashback New Member

    I didn't test this yet, as I did everything manually so far.
    Feel free to test.
    I used AI to summarize my thoughts.
    Thank you.

    Hello everyone,

    after running several ISPConfig servers I ran into a common issue: mail clients sometimes show SSL warnings because the server delivers the hostname certificate instead of the correct domain certificate.

    Managing certificates for multiple domains with mail.* and webmail.* subdomains can also become complicated.

    So I created a small automation setup that:

    - collects mail.* and webmail.* domains from the ISPConfig database
    - generates a SAN certificate
    - updates Apache ServerAlias automatically
    - reloads Postfix and Dovecot
    - protects against Let's Encrypt rate limits
    - creates configuration backups

    The system is now running stable in production and maybe it helps someone with a similar setup.

    --------------------------------------------------
    PROBLEM
    --------------------------------------------------

    Typical issues on multi-domain ISPConfig setups:

    - mail clients show SSL warnings
    - Postfix / Dovecot deliver the hostname certificate
    - new domains must be manually added to certificates
    - Apache sometimes serves the wrong SSL vhost

    Example structure:

    example-host.tld
    mail.example-host.tld
    webmail.example-host.tld
    mail.customer-domain1.tld
    webmail.customer-domain1.tld
    mail.customer-domain2.tld
    webmail.customer-domain2.tld

    --------------------------------------------------
    PART 1 — BASIC SETUP
    --------------------------------------------------

    DNS configuration

    Each domain needs:

    Code:
    mail.example-domain.tld      -> server-ip
    webmail.example-domain.tld   -> server-ip
    
    --------------------------------------------------

    Apache webmail vhost

    File:

    Code:
    /etc/apache2/sites-available/webmail.example-host.tld.vhost
    
    Add ServerAlias entries:

    Code:
    ServerAlias webmail.example-host.tld webmail.example-domain.tld
    
    Then test and reload Apache:

    Code:
    apache2ctl configtest
    systemctl reload apache2
    
    --------------------------------------------------

    Create certificate using acme.sh

    Code:
    /root/.acme.sh/acme.sh --issue --force --keylength ec-256 \
    -d example-host.tld \
    -d mail.example-host.tld \
    -d webmail.example-host.tld \
    -d mail.example-domain.tld \
    -d webmail.example-domain.tld \
    -w /var/www/example-host.tld/web \
    --reloadcmd "systemctl restart dovecot postfix && systemctl reload apache2"
    
    --------------------------------------------------

    Configure mail services

    Dovecot config:

    Code:
    /etc/dovecot/conf.d/10-ssl.conf
    
    Code:
    ssl_cert = </root/.acme.sh/example-host.tld_ecc/fullchain.cer
    ssl_key  = </root/.acme.sh/example-host.tld_ecc/example-host.tld.key
    
    Postfix config:

    Code:
    postconf -e 'smtpd_tls_cert_file = /root/.acme.sh/example-host.tld_ecc/fullchain.cer'
    postconf -e 'smtpd_tls_key_file = /root/.acme.sh/example-host.tld_ecc/example-host.tld.key'
    
    Restart services:

    Code:
    systemctl restart dovecot postfix
    
    --------------------------------------------------
    PART 2 — AUTOMATION SCRIPT
    --------------------------------------------------

    The following script:

    - reads domains from ISPConfig database
    - updates Apache ServerAlias automatically
    - creates SAN certificates
    - avoids Let's Encrypt rate limits
    - creates configuration backups

    Script location:

    Code:
    /usr/local/bin/run_master_ssl.sh
    
    Code:
    #!/bin/bash
    set -e
    
    DYNAMIC_WEBROOT=$1
    VHOST_FILE="/etc/apache2/sites-available/webmail.example-host.tld.vhost"
    DOVECOT_SSL="/etc/dovecot/conf.d/10-ssl.conf"
    HASH_FILE="/root/.master_ssl_domain_hash"
    BACKUP_DIR="/root/backup_configs/$(date +%Y-%m-%d)"
    
    [ -z "$DYNAMIC_WEBROOT" ] && { echo "ERROR: Webroot variable empty"; exit 1; }
    [ ! -d "$DYNAMIC_WEBROOT" ] && { echo "ERROR: Webroot path missing"; exit 1; }
    [ ! -f "$VHOST_FILE" ] && { echo "ERROR: Apache vhost missing"; exit 1; }
    [ ! -f "$DOVECOT_SSL" ] && { echo "ERROR: Dovecot SSL config missing"; exit 1; }
    
    DB_PASS=$(grep password /usr/local/ispconfig/server/lib/mysql_clientdb.conf | cut -d\' -f2)
    
    DB_DOMAINS=$(mysql -u root -p"$DB_PASS" dbispconfig -e \
    "SELECT domain FROM web_domain WHERE active = 'y' AND (domain LIKE 'mail.%' OR domain LIKE 'webmail.%')" -N | sort)
    
    ALIAS_LIST="webmail.example-host.tld"
    ACME_DOMAINS="-d example-host.tld -d mail.example-host.tld -d webmail.example-host.tld"
    
    for d in $DB_DOMAINS; do
        if [[ $d == "mail.example-host.tld" || $d == "webmail.example-host.tld" ]]; then continue; fi
        ACME_DOMAINS="$ACME_DOMAINS -d $d"
        if [[ $d == webmail.* ]]; then ALIAS_LIST="$ALIAS_LIST $d"; fi
    done
    
    NEW_HASH=$(echo "$ACME_DOMAINS" | md5sum | cut -d' ' -f1)
    OLD_HASH=$(cat "$HASH_FILE" 2>/dev/null || echo "")
    
    if [ "$NEW_HASH" = "$OLD_HASH" ]; then
        exit 0
    fi
    
    mkdir -p "$BACKUP_DIR"
    cp "$VHOST_FILE" "$BACKUP_DIR/"
    cp "$DOVECOT_SSL" "$BACKUP_DIR/"
    
    sed -i "s/ServerAlias .*/ServerAlias $ALIAS_LIST/" "$VHOST_FILE"
    
    if apache2ctl configtest > /dev/null 2>&1; then
        systemctl reload apache2
    else
        cp "$BACKUP_DIR/$(basename $VHOST_FILE)" "$VHOST_FILE"
        apache2ctl configtest && systemctl reload apache2
        exit 1
    fi
    
    if /root/.acme.sh/acme.sh --issue --force --keylength ec-256 $ACME_DOMAINS -w "$DYNAMIC_WEBROOT" --reloadcmd "systemctl restart dovecot postfix && systemctl reload apache2"; then
        echo "$NEW_HASH" > "$HASH_FILE"
    else
        echo "ERROR: certificate generation failed"
        exit 1
    fi
    
    sed -i "s|^ssl_cert =.*|ssl_cert = </root/.acme.sh/example-host.tld_ecc/fullchain.cer|" "$DOVECOT_SSL"
    sed -i "s|^ssl_key =.*|ssl_key = </root/.acme.sh/example-host.tld_ecc/example-host.tld.key|" "$DOVECOT_SSL"
    
    postconf -e "smtpd_tls_cert_file = /root/.acme.sh/example-host.tld_ecc/fullchain.cer"
    postconf -e "smtpd_tls_key_file = /root/.acme.sh/example-host.tld_ecc/example-host.tld.key"
    
    systemctl restart dovecot postfix
    
    --------------------------------------------------
    RESULT
    --------------------------------------------------

    This setup ensures:

    - mail clients always receive the correct certificate
    - new domains are automatically included
    - Apache configuration stays clean
    - Let's Encrypt rate limits are avoided
    - configuration backups are created
     

Share This Page