bg-tutorials

How to Install an ACME SSL Certificate on Remote Desktop

Remote Desktop presents a self-signed certificate out of the box, which is why users get a warning every time they connect. You can replace it with a publicly trusted certificate and keep it renewed automatically using win-acme, including certificates from a commercial certificate authority that requires External Account Binding. The part that needs care is the last step, because binding a certificate to the RDP listener is not something win-acme does directly.

One point of vocabulary before the steps, because it decides which script you need. Plain Remote Desktop listens on TCP 3389 and secures that connection with TLS. It is not served over HTTPS. RD Gateway is the component that tunnels RDP over HTTPS on port 443, and a full Remote Desktop Services deployment has several roles that each hold a certificate. This guide covers the plain listener; win-acme ships separate scripts for the other cases, named for what they do.

Automating renewal matters more each year. Under CA/Browser Forum ballot SC-081v3, publicly trusted TLS certificates have been capped at 200 days since March 15, 2026, dropping to 100 days on March 15, 2027 and to 47 days on March 15, 2029.

Before you begin

  • Administrator access to the Windows Server, and an elevated PowerShell window. win-acme requires administrator privileges, and so does writing to the RDP listener configuration.
  • A public host name that resolves to this server. The certificate is issued for that name, and users have to connect to it rather than to the machine’s internal name, or the certificate will not match.
  • Inbound TCP port 80 reachable from the internet for HTTP-01 validation. Only during validation; RDP itself does not use it.
  • Your CA’s ACME directory URL, EAB Key ID and EAB HMAC Key.
  • A TLS-capable security layer on the listener. If Remote Desktop is set to the legacy RDP security layer rather than negotiating TLS, a certificate makes no difference; leave it on the default negotiate setting or require TLS.

Step 1: Download win-acme

  1. Open the win-acme releases page and take the newest stable release. The project site holds the documentation.
  2. Choose your architecture, normally x64, and take the pluggable build rather than the trimmed one. The pluggable archive is roughly 35 MB against 13 MB, and it is the one that can take extra plugins if you later need DNS validation.
  3. Extract it to a permanent folder. win-acme recommends %programfiles%\win-acme, and the reason is concrete: the scheduled task stores the path to the executable, so a temporary folder means renewals stop working once it is cleaned up.
  4. Confirm the Scripts subfolder came with it. That is where ImportRDListener.ps1 lives, and Step 2 depends on it.

Step 2: Request the certificate and bind it to the listener

Run this from an elevated PowerShell window, substituting your own host name, directory URL and EAB credentials.

& "C:\Program Files\win-acme\wacs.exe" `
  --source manual `
  --host "rdp.example.com" `
  --validation selfhosting `
  --store certificatestore `
  --installation script `
  --script "C:\Program Files\win-acme\Scripts\ImportRDListener.ps1" `
  --scriptparameters "{CertThumbprint}" `
  --baseuri "https://acme.yourca.example/v2/DV" `
  --emailaddress "[email protected]" `
  --eab-key-identifier "YOUR_EAB_KEY_ID" `
  --eab-key "YOUR_EAB_HMAC_KEY" `
  --accepttos

The backtick is PowerShell’s line continuation and only works as the final character on a line, so watch for a trailing space if you retype it. Putting the whole command on one line without any backticks works just as well.

What the arguments do, and where the common mistakes are:

  • --source manual with --host names the certificate directly, since there is no IIS site to read the name from. You will see --target manual in older material; that spelling is marked obsolete in win-acme, and --source is the current one.
  • --validation selfhosting uses win-acme’s own listener on port 80. It is the default anyway, and it does not need IIS.
  • --store certificatestore puts the certificate in the Windows certificate store. Which store depends on the machine: win-acme writes to WebHosting when IIS 8 or later is running and to Personal otherwise, so on a Remote Desktop host with no IIS it lands in Personal. Either way the script in the next step puts it where the listener needs it.
  • --installation script with --script and --scriptparameters is the binding. {CertThumbprint} is a placeholder win-acme substitutes with the new certificate’s thumbprint, and the script takes it as its single positional parameter.
  • --eab-key must be passed exactly as the CA gave it, because it is already base64url encoded. If registration is refused while both EAB values look correct, add --eab-algorithm: win-acme defaults to HS256 and also accepts HS384 and HS512, and a CA expecting a different one rejects a perfectly good key.

There is no --installation rdp. win-acme documents two installation plugins, IIS bindings and Script, and the source tree contains only those two plus an internal do-nothing option. A command using an rdp plugin fails on that argument before anything is requested.

What the script does, and the one thing that can break it

Knowing the two things ImportRDListener.ps1 does makes every later problem easy to place.

First it searches the local machine store for the thumbprint it was given, and if the certificate is not already in Personal, it copies it there. That step exists precisely because win-acme’s certificate store plugin writes to WebHosting whenever IIS 8 or later is present, and to Personal when it is not, while the RDP listener always needs it in Personal; on a server without IIS it is already there and the copy is a no-op. Second, it writes that thumbprint into the SSLCertificateSHA1Hash property of the Win32_TSGeneralSetting class in the root\cimv2\TerminalServices namespace, which is the documented, writable setting that tells Remote Desktop which certificate to present.

The catch is how it performs that write: it calls wmic, the old WMI command-line tool. Microsoft deprecated wmic in Windows 10 version 21H1 and the equivalent Windows Server release, and it has been progressively removed since. On recent Windows 11 builds it is disabled by default, and from Windows Server 2025 it is a Feature on Demand rather than something present out of the box. WMI itself is unaffected; only the command-line tool went away.

So on a current server the script can fail at its final line while everything before it worked. Check whether the tool is present, and if not, either add the feature or do the write from PowerShell instead:

Get-Command wmic -ErrorAction SilentlyContinue
Get-WindowsCapability -Online -Name "WMIC*"

The capability name differs between builds, so read it from that output and install it with Add-WindowsCapability rather than copying a name from a guide, and treat it as a stopgap: Microsoft has been withdrawing the capability itself through 2026, so on the newest builds there is nothing left to install. If you would rather not depend on a tool that is on its way out, replace the script’s final line with the PowerShell equivalent:

$ts = Get-WmiObject -Namespace root\cimv2\TerminalServices `
  -Class Win32_TSGeneralSetting -Filter "TerminalName='RDP-Tcp'" `
  -Authentication PacketPrivacy
$ts.SSLCertificateSHA1Hash = $NewCertThumbprint
$ts.Put()

The -Authentication PacketPrivacy is not optional decoration. Microsoft’s own reference states that connecting to the TerminalServices namespace requires packet privacy, and wmic sets that authentication level by default, which is why a naive PowerShell translation that omits it fails where the original worked.

Step 3: Verify the binding took

Read the listener configuration back. There is a property that answers the question directly:

Get-WmiObject -Namespace root\cimv2\TerminalServices `
  -Class Win32_TSGeneralSetting -Filter "TerminalName='RDP-Tcp'" `
  -Authentication PacketPrivacy |
  Select-Object TerminalName, SSLCertificateSHA1Hash, SSLCertificateSHA1HashType

SSLCertificateSHA1HashType reports where the current certificate came from: 1 means the default self-signed certificate, 2 means one enforced by group policy, and 3 means custom. After a successful run you want 3, with the hash matching the certificate win-acme just issued. A value of 1 means the binding never happened, whatever the rest of the output said.

If it still reads 2, group policy is overriding your setting. Look for the policy that specifies a server authentication certificate template for Remote Desktop, because that will keep winning until it is changed.

Then connect for real. Open mstsc.exe, connect to the public host name rather than the internal one, and confirm no certificate warning appears. Connecting by IP address or by the machine’s short name will still warn, because the name will not match the certificate; that is correct behaviour rather than a failed installation.

Step 4: Confirm renewal is scheduled

& "C:\Program Files\win-acme\wacs.exe" --list --baseuri "https://acme.yourca.example/v2/DV"

Passing --baseuri here is not optional bookkeeping. win-acme keeps a separate configuration directory per ACME server under C:\ProgramData\win-acme\, so a bare --list reports on the default endpoint and shows nothing, which looks exactly like having no renewal configured.

In Task Scheduler you will find a task named win-acme renew followed by your CA’s hostname in brackets. Because the installation arguments are stored with the renewal, each renewal re-runs the script and re-binds the new thumbprint without any action from you.

Renewal timing is worth one look. win-acme renews 55 days after issuance by default, a static schedule counted from issuance rather than from expiry. In practice it usually follows the certificate authority instead, because ACME Renewal Information is enabled by default and the CA’s published window takes precedence where the endpoint supports it. The gap to know about is a CA without that support: the static schedule then applies, floored only by RenewalMinimumValidDays, which is unset out of the box and read as 7 days when unset. On today’s lifetimes the 55-day schedule fires long before that floor, but once certificates live for less than about two months the floor is what triggers renewal and a week is a thin margin, so raise it in settings.json next to wacs.exe if your CA does not publish renewal information.

Prove the whole path once rather than waiting:

& "C:\Program Files\win-acme\wacs.exe" --renew --force --baseuri "https://acme.yourca.example/v2/DV"

Then re-run the verification from Step 3 and confirm the thumbprint changed. Certificate authorities apply rate limits, so use --force for a single test rather than in a loop.

When it does not work

  • The run fails on an argument. Check for --installation rdp or --target carried over from an older guide. Neither is valid.
  • The certificate was issued but RDP still shows the old one. Read SSLCertificateSHA1HashType. If it is 1, the script did not complete; run it by hand with a known thumbprint and read its output, since it prints whether the write succeeded.
  • The script reports the thumbprint was not found in the store. That points at the store plugin rather than the script. Confirm --store certificatestore was used and look in WebHosting as well as Personal.
  • The final line fails on a current server. That is the wmic problem above.
  • Validation times out. Confirm inbound port 80 reaches this server and that nothing else holds it. win-acme shares port 80 with IIS through the Windows HTTP stack, but a non-Microsoft web server on that port stops its listener from starting, and it says so explicitly.
  • Users still see a warning. Check they are connecting to the name on the certificate. Add --verbose to any win-acme command for the detailed log, which is also written under the configuration directory.

For error strings that come from the ACME protocol rather than from win-acme, such as badNonce, unauthorized or a CAA record refusing issuance, see our guide to fixing ACME SSL certificate errors.

Frequently Asked Questions

Is there a win-acme plugin that installs certificates to RDP?

No. win-acme documents exactly two installation plugins, IIS bindings and Script, and the source contains only those plus an internal do-nothing option. Commands featuring an rdp installation plugin cannot run. What does exist, and does the job, is the ImportRDListener.ps1 script bundled with win-acme, driven through the Script plugin.

Do I need port 443 open?

Not for plain Remote Desktop, which listens on TCP 3389. During issuance you need port 80 for HTTP-01 validation, and after that neither 80 nor 443 is involved. RD Gateway is different: it genuinely publishes RDP over HTTPS on 443, and it has its own bundled script.

Are the steps the same for a Remote Desktop Services deployment?

No, and this is worth getting right before you start. A full RDS deployment holds certificates for several roles, including RD Web Access, RD Gateway, the connection broker for publishing and the broker for redirection, and setting the listener thumbprint on one host does not configure any of them. win-acme ships separate scripts for those cases, alongside the listener script used here. Pick the one that matches your deployment rather than adapting this one.

Will this work on Windows Server Core?

Yes. Nothing here needs a graphical interface: win-acme runs from the command line, the script is PowerShell, and the setting it writes is a WMI property. The one thing to check on Server Core, as on any current build, is whether wmic is present, since the bundled script uses it.

Do I need IIS installed?

No. The self-hosting validation plugin runs win-acme’s own listener for the challenge, so no web server is required. IIS only enters the picture if it already occupies port 80, in which case the two share it through the Windows HTTP stack without conflict.

Why does the certificate end up in the Personal store?

Because the RDP listener needs it there, and win-acme’s store plugin does not always put it there: it writes to WebHosting when IIS 8 or later is running and to Personal when it is not. The bundled script handles the difference: it looks the thumbprint up anywhere in the local machine store and copies the certificate into Personal before setting it on the listener. Seeing the certificate in both places afterwards is expected.

For more on the protocol behind all of this, see what the ACME protocol is and our ACME SSL certificates page. For the same client on a web server, see installing an ACME SSL certificate on Windows IIS, and for a certificate installed by hand, installing an SSL certificate on Remote Desktop Services.

Save 10% on SSL Certificates when ordering from SSL Dragon today!

Fast issuance, strong encryption, 99.99% browser trust, dedicated support, and 25-day money-back guarantee. Coupon code: SAVE10

A detailed image of a dragon in flight
Written by

I've been writing for SSL Dragon for over 10 years, focusing entirely on SSL certificates and digital security. My job is to take complex cybersecurity topics and strip away the jargon, making sure you get the clear, practical information you need to keep your website safe.

Avatar of Sergiu Rosca
Technical Review by Sergiu Rosca

Sergiu Rosca is the core web developer behind SSL Dragon. He manages the technical infrastructure, platform performance, and backend integrations that keep the site running smoothly and securely. At SSL Dragon, Sergiu shares practical insights on web development, site optimization, and technical troubleshooting.

All SSL Dragon installation guides are tested on live server environments and undergo a strict peer-review process to ensure your infrastructure remains secure. Read our full Editorial Policy.