How to Configure SSL/TLS in IIS on Windows Server 2022

Securing your IIS websites with SSL/TLS is essential for protecting data in transit and establishing trust with visitors. Windows Server 2022 ships with IIS 10, which supports modern TLS configurations including TLS 1.3. This guide covers obtaining and importing SSL certificates, binding them to IIS sites, enforcing HTTPS, configuring TLS protocol versions and cipher suites, and managing certificate renewals.

Types of SSL Certificates

Before configuring SSL, understand the certificate types available. A self-signed certificate is generated on the server and signed by itself. Browsers will display a security warning because no trusted Certificate Authority (CA) has vouched for it. Self-signed certificates are appropriate for development, testing, and internal tools where you control the clients. A CA-signed certificate is issued by a trusted Certificate Authority (Let’s Encrypt, DigiCert, Sectigo, etc.) and is trusted by browsers automatically. This is required for any public-facing website.

Creating a Self-Signed Certificate

Generate a self-signed certificate for development purposes using PowerShell. This command creates a certificate valid for one year with the specified DNS name and stores it in the local machine’s certificate store:

$cert = New-SelfSignedCertificate `
    -DnsName "mysite.local", "www.mysite.local" `
    -CertStoreLocation "Cert:LocalMachineMy" `
    -NotAfter (Get-Date).AddYears(1) `
    -KeyAlgorithm RSA `
    -KeyLength 2048 `
    -HashAlgorithm SHA256 `
    -FriendlyName "MyLocalSite SSL"

Write-Host "Certificate thumbprint: $($cert.Thumbprint)"

Importing a CA-Signed Certificate

If you have a certificate from a CA delivered as a PFX file (which contains both the certificate and private key), import it into the Windows certificate store:

# Import PFX certificate into the Local Machine Personal store
$pfxPath = "C:certsmysite.pfx"
$pfxPassword = ConvertTo-SecureString -String "YourPFXPassword" -Force -AsPlainText

Import-PfxCertificate -FilePath $pfxPath -CertStoreLocation "Cert:LocalMachineMy" -Password $pfxPassword

After importing, get the thumbprint of the certificate — you will need it to bind it to IIS:

Get-ChildItem -Path "Cert:LocalMachineMy" | Select-Object FriendlyName, Subject, Thumbprint, NotAfter | Format-Table -AutoSize

If you received the certificate as separate CRT and KEY files (common from Let’s Encrypt or OpenSSL workflows), convert them to PFX first using OpenSSL:

openssl pkcs12 -export -out mysite.pfx -inkey mysite.key -in mysite.crt -certfile chain.crt -passout pass:YourPassword

Binding a Certificate to an IIS Site

Once your certificate is in the certificate store, add an HTTPS binding to your IIS site and assign the certificate. The certificate is referenced by its thumbprint:

# Add HTTPS binding on port 443 with host header
New-WebBinding -Name "MySite" -Protocol "https" -Port 443 -HostHeader "mysite.example.com" -IPAddress "*" -SslFlags 1

# Get the binding object and assign the certificate
$binding = Get-WebBinding -Name "MySite" -Protocol "https"
$thumbprint = "PASTE_YOUR_THUMBPRINT_HERE"
$cert = Get-Item -Path "Cert:LocalMachineMy$thumbprint"
$binding.AddSslCertificate($cert.Thumbprint, "My")

The -SslFlags 1 parameter enables SNI (Server Name Indication), which is required when hosting multiple HTTPS sites on the same IP address. Without SNI (SslFlags 0), the certificate is bound to the IP address rather than the host name.

Alternatively, use netsh to bind a certificate to an IP:port combination for non-SNI configurations:

# Bind certificate to 0.0.0.0:443 (all IPs on port 443) without SNI
$appid = "{$(New-Guid)}"
netsh http add sslcert ipport=0.0.0.0:443 certhash=$thumbprint appid=$appid certstorename=My

Requiring SSL — Redirecting HTTP to HTTPS

After configuring HTTPS, force all HTTP traffic to redirect to HTTPS. The cleanest way is using the IIS URL Rewrite module. First install URL Rewrite (available from Microsoft or via Web Platform Installer), then add a rewrite rule to the site’s web.config:



  
    
      
        
          
          
            
          
          
        
      
    
  

To require SSL at the IIS level (returning 403.4 instead of redirecting), configure the SSL settings for the site or a specific path:

Set-WebConfigurationProperty -Filter "system.webServer/security/access" -PSPath "IIS:SitesMySite" -Name "sslFlags" -Value "Ssl"

Configuring TLS Protocol Versions

Windows Server 2022 enables TLS 1.2 and TLS 1.3 by default and disables SSL 2.0, SSL 3.0, and TLS 1.0. However, TLS 1.1 may still be enabled. The protocol settings are controlled via the Windows Registry under HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocols.

To explicitly disable TLS 1.1 and TLS 1.0 using PowerShell:

function Disable-TlsProtocol {
    param([string]$Protocol)
    $path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocols$Protocol"
    
    # Disable for server role
    New-Item -Path "$pathServer" -Force | Out-Null
    Set-ItemProperty -Path "$pathServer" -Name "Enabled" -Value 0 -Type DWord
    Set-ItemProperty -Path "$pathServer" -Name "DisabledByDefault" -Value 1 -Type DWord
    
    # Disable for client role
    New-Item -Path "$pathClient" -Force | Out-Null
    Set-ItemProperty -Path "$pathClient" -Name "Enabled" -Value 0 -Type DWord
    Set-ItemProperty -Path "$pathClient" -Name "DisabledByDefault" -Value 1 -Type DWord
    
    Write-Host "$Protocol disabled."
}

Disable-TlsProtocol "TLS 1.0"
Disable-TlsProtocol "TLS 1.1"
Disable-TlsProtocol "SSL 2.0"
Disable-TlsProtocol "SSL 3.0"

To explicitly enable TLS 1.2 and TLS 1.3 (verify they are on):

function Enable-TlsProtocol {
    param([string]$Protocol)
    $path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocols$Protocol"
    New-Item -Path "$pathServer" -Force | Out-Null
    Set-ItemProperty -Path "$pathServer" -Name "Enabled" -Value 1 -Type DWord
    Set-ItemProperty -Path "$pathServer" -Name "DisabledByDefault" -Value 0 -Type DWord
    Write-Host "$Protocol enabled for server."
}

Enable-TlsProtocol "TLS 1.2"
Enable-TlsProtocol "TLS 1.3"

A reboot is required for registry changes to take effect. Always test changes in a non-production environment first to avoid locking out legitimate clients.

Using IIS Crypto Tool

IIS Crypto by Nartac Software is a free GUI tool that simplifies TLS/cipher configuration on Windows Server. It reads and writes the same registry keys as the manual PowerShell approach but provides a visual interface with preset templates (Best Practices, PCI, FIPS 140-2, etc.). Download from https://www.nartac.com/Products/IISCrypto. Run it as Administrator, select the “Best Practices” template, click Apply, and reboot. The command-line version (IIS Crypto CLI) can be scripted:

IISCryptoCli.exe /template best
# Apply and reboot
IISCryptoCli.exe /reboot

Disabling Weak Cipher Suites

Beyond protocol versions, individual cipher suites should be audited. Weak ciphers like RC4, DES, 3DES, and export-grade ciphers should be disabled. Use PowerShell to disable specific ciphers via the registry:

# Disable RC4 ciphers
$rc4Variants = @("RC4 40/128", "RC4 56/128", "RC4 64/128", "RC4 128/128")
foreach ($cipher in $rc4Variants) {
    $path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELCiphers$cipher"
    New-Item -Path $path -Force | Out-Null
    Set-ItemProperty -Path $path -Name "Enabled" -Value 0 -Type DWord
}

# Disable Triple DES
$path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELCiphersTriple DES 168"
New-Item -Path $path -Force | Out-Null
Set-ItemProperty -Path $path -Name "Enabled" -Value 0 -Type DWord

# Disable NULL cipher
$path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELCiphersNULL"
New-Item -Path $path -Force | Out-Null
Set-ItemProperty -Path $path -Name "Enabled" -Value 0 -Type DWord

SNI for Multiple Certificates on the Same IP

Server Name Indication (SNI) is a TLS extension that allows the client to specify which hostname it is connecting to during the TLS handshake, before the certificate is presented. This allows the server to select the correct certificate for each hostname — enabling multiple HTTPS sites on a single IP address, each with its own certificate.

When creating HTTPS bindings with host headers, set -SslFlags 1 to enable SNI:

# Site 1 with SNI
New-WebBinding -Name "Site1" -Protocol "https" -Port 443 -HostHeader "site1.example.com" -IPAddress "*" -SslFlags 1
$b1 = Get-WebBinding -Name "Site1" -Protocol "https"
$b1.AddSslCertificate("THUMBPRINT_CERT1", "My")

# Site 2 with SNI (same IP, same port, different cert)
New-WebBinding -Name "Site2" -Protocol "https" -Port 443 -HostHeader "site2.example.com" -IPAddress "*" -SslFlags 1
$b2 = Get-WebBinding -Name "Site2" -Protocol "https"
$b2.AddSslCertificate("THUMBPRINT_CERT2", "My")

SNI requires all clients to support it. All modern browsers and operating systems (Windows Vista+, iOS 4+, Android 4+) support SNI. Very old clients (Internet Explorer on Windows XP) do not, but these represent a negligible fraction of modern traffic.

Certificate Renewal

SSL certificates expire and must be renewed. For Let’s Encrypt certificates, the win-acme (WACS) tool handles automated renewal on Windows. Download it from https://www.win-acme.com and run:

# Interactive mode — follows prompts to create and bind a certificate
wacs.exe

# Renew all existing certificates (run as scheduled task)
wacs.exe --renew --baseuri "https://acme-v02.api.letsencrypt.org/"

Set up a scheduled task to run renewal daily (certificates are only renewed when they are within 30 days of expiry):

$action = New-ScheduledTaskAction -Execute "C:toolswacswacs.exe" -Argument "--renew --noconsole"
$trigger = New-ScheduledTaskTrigger -Daily -At "3:00AM"
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
Register-ScheduledTask -TaskName "Let's Encrypt Renewal" -Action $action -Trigger $trigger -Principal $principal

For CA-issued certificates, monitor expiry dates and plan renewals at least 30 days before expiration. Check all certificate expiry dates on the server:

Get-ChildItem -Path "Cert:LocalMachineMy" | 
    Where-Object { $_.NotAfter -lt (Get-Date).AddDays(60) } | 
    Select-Object FriendlyName, Subject, Thumbprint, NotAfter | 
    Sort-Object NotAfter | 
    Format-Table -AutoSize

Properly configured TLS on IIS — with modern protocol versions, strong cipher suites, SNI for multi-site deployments, and automated certificate renewal — provides a secure foundation for all web traffic on Windows Server 2022.