Lets Encrypt automatic SSL Certificate

Forum for things that doesn't really have anything to do with hMailServer. Such as php.ini, beer, etc etc.
Post Reply
Normal user
Normal user
Posts: 31
Joined: 2016-04-09 23:28

Lets Encrypt automatic SSL Certificate

Post by tester02 » 2019-04-24 21:09

I just wantet to share my solution for the automatic renewal and deployment of Lets Encrypt certificates.

Some preconditions that have to be met:
- Windows Server with the build in DNS Server enabled
- OpenSSL for Windows
- Certify SSL Manager (https://certifytheweb.com)
- and of course hmailserver.
(and not needed but works nice for me
- Win Server Role IIS
- Win Server Role RRAS for VPN)

The Certify SSL Manager is configured to obtain every 60 Days the renewed certificate, install it in the local Certificate Store and deploy it to the webserver (IIS), the VPN (RRAS) and hmailserver. For hmailserver its necessary to export and convert the certificate beforehand. That works via a powershell file (RRAS.ps1) that is called from the Certify SSL Manager in the post processing.

The SSL certificate is a multidomain with wildcards certificate, but all on one IP-Adress and with one hmailserver configured for all these domains.

Code for RRAS.ps1

Code: Select all


# Store Certificate in variable
$cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Thumbprint -match $result.ManagedItem.CertificateThumbprintHash}

# Stop RRAS, set Certificate, start RRAS
Import-Module RemoteAccess
Stop-Service RemoteAccess
Set-RemoteAccess -SslCertificate $cert
Start-Service RemoteAccess

# Export Certificate - creating a file named ExpireDate.pfx
$mypwd = ConvertTo-SecureString -String "SecretPassword" -Force -AsPlainText
$Name2 = Get-ChildItem -Path 'Cert:\localmachine\My' | Where-Object { $_.hasPrivateKey } | gci | select NotAfter
$Name1 = $Name2.NotAfter | measure -Maximum | select Maximum | Out-String
$Name1 = $Name1.Remove(0,44)
$Name = $Name1.Remove(10,15)
Get-ChildItem -Path 'Cert:\localmachine\My' | Where-Object { $_.hasPrivateKey } | Export-PfxCertificate -FilePath C:\Path\Zertifikate\$Name.pfx -Password $mypwd

# Convert Certificate to pem
set OPENSSL_CONF=C:\Path\OpenSSL\bin\openssl.cfg
C:\Path\OpenSSL\bin\openssl.exe pkcs12 -in C:\Path\Zertifikate\$Name.pfx -out C:\Path\Zertifikate\temp.pem -nodes -password pass:SecretPassword
C:\Path\OpenSSL\bin\openssl.exe pkey -in C:\Path\temp.pem -out C:\Path\Zertifikate\$Name.Private.pem

# Modify the certificate file to strip not needed lines and match the order: first certificat, second intermediate, third root. 
# Im my case it's ALWAYS wrong: certificate, root, intermediate.
$SLine = select-string -pattern "BEGIN CERTIFICATE" -path "C:\Path\Zertifikate\temp.pem"
$ELine = select-string -pattern "END CERTIFICATE" -path "C:\Path\Zertifikate\temp.pem"

$Certificate = for ($i = ($SLine[0].LineNumber - 1); $i -le ($ELine[0].LineNumber - 1); $i++) {
	Get-Content -path C:\Path\Zertifikate\temp.pem | Select -Index $i
$Root = for ($i = ($SLine[1].LineNumber - 1); $i -le ($ELine[1].LineNumber - 1); $i++) {
	Get-Content -path C:\Path\Zertifikate\temp.pem | Select -Index $i
$Intermediate = for ($i = ($SLine[2].LineNumber - 1); $i -le ($ELine[2].LineNumber - 1); $i++) {
	Get-Content -path C:\Path\Zertifikate\temp.pem | Select -Index $i

# Remove temp file --> certificate with private key, certificates and not needed lines
Remove-Item C:\Path\Zertifikate\temp.pem

$Preperation = "$Certificate" + " " + "$Intermediate" + " " + "$Root"
$Preperation = $Preperation -replace "BEGIN CERTIFICATE","BEGIN_CERTIFICATE"
$Preperation = $Preperation -replace "END CERTIFICATE","END_CERTIFICATE"
$Preperation = $Preperation -replace ' ',"`n"
$Preperation = $Preperation -replace "BEGIN_CERTIFICATE","BEGIN CERTIFICATE"
$Preperation = $Preperation -replace "END_CERTIFICATE","END CERTIFICATE"

# Write and trim files, named ExpireDate.Certificat.pem and ExpireDate.Private.pem
$Preperation > C:\Path\$Name.Certificate.pem
(gc C:\Path\Zertifikate\$Name.Certificate.pem) | Foreach {$_.TrimEnd()} | where {$_ -ne ""} | Set-Content C:\Path\Zertifikate\$Name.Certificate.pem
(gc C:\Path\Zertifikate\$Name.Private.pem) | Foreach {$_.TrimEnd()} | where {$_ -ne ""} | Set-Content C:\Path\Zertifikate\$Name.Private.pem

# Deploy files to hmailserver
Stop-Service hmailserver
Copy-Item "C:\Path\Zertifikate\$Name.Certificate.pem" "C:\Program Files\hMailServer\SSL\Certificate.pem"
Copy-Item "C:\Path\Zertifikate\$Name.Private.pem" "C:\Program Files\hMailServer\SSL\Private.pem"
Start-Service hmailserver

HMailServer SSL Certificate Config

Certify SSL Config Part 1

Certify SSL Config Part 2
It works with multiple domains and their wildcards.
Last edited by tester02 on 2019-04-24 21:20, edited 2 times in total.

Normal user
Normal user
Posts: 31
Joined: 2016-04-09 23:28

Re: Lets Encrypt automatic SSL Certificate

Post by tester02 » 2019-04-24 21:10

Certify SSL Config Part 3

Certify SSL Config Part 4

Certify SSL Config Part 5

I'm not quite sure why but if I replaced the string "C:\Path\" with $Path = "C:\DifferentPath" the code would fail.
In addition in the line

Code: Select all

C:\OpenSSL\bin\openssl.exe pkcs12 -in C:\Path\Zertifikate\$Name.pfx -out C:\Path\Zertifikate\temp.pem -nodes -password pass:SecureSecret
the password wouldn't work with $mypwd or $differentVariable. It had to be the password in plaintext.

If anyone likes to contibute or comment I'm glad for some feedback and code improvement.

Normal user
Normal user
Posts: 45
Joined: 2014-11-11 17:29
Location: Italy

Re: Lets Encrypt automatic SSL Certificate

Post by alescan » 2019-11-20 18:20

Don't know if you still need but i just created this topic:
https://www.hmailserver.com/forum/viewt ... 21&t=34562
HMS 5.6.7 B2425 on Win Server 2016 Standard with SQL Server 2014 SP2

Post Reply