CrtMgr Blog - SSL/TLS Certificate Management Insights

Expert insights on SSL/TLS certificate management, types, deployment, and best practices

SSL/TLS Certificate Deployment Guide: Nginx, Apache, and IIS

SSL TLS Nginx Apache IIS Deployment Certificate Chain

Deploying SSL/TLS certificates correctly is crucial for securing your web applications. This guide covers certificate installation on the three most popular web servers: Nginx, Apache, and IIS, including proper certificate chain configuration.

Understanding Certificate Chains

Before deployment, it’s essential to understand certificate chains.

What is a Certificate Chain?

A certificate chain (or chain of trust) is a sequence of certificates where each certificate is signed by the next certificate in the chain:

Root CA Certificate (trusted by browsers)
    ↓ (signs)
Intermediate CA Certificate
    ↓ (signs)
Your Server Certificate

Why Certificate Chains Matter

Browsers and clients need to verify that your certificate is trusted. They do this by:

  1. Checking your server certificate
  2. Following the chain to intermediate certificates
  3. Verifying the chain ends at a trusted root CA

If the chain is incomplete, users will see security warnings!

Certificate Chain Components

  1. Server Certificate (leaf certificate)

    • Your domain’s certificate
    • Example: example.com.crt
  2. Intermediate Certificate(s)

    • Issued by root CA to sign server certificates
    • One or more certificates
    • Example: intermediate.crt or ca-bundle.crt
  3. Root Certificate

    • Self-signed, trusted by browsers
    • Usually NOT included in server configuration
    • Already in browser/OS trust stores

Fullchain vs. Certificate + Chain

Fullchain:

  • Single file with server cert + intermediates
  • Example: fullchain.pem
  • Most convenient for Nginx

Separate files:

  • Server certificate: example.com.crt
  • Intermediate chain: ca-bundle.crt or intermediate.crt
  • Common with Apache

Nginx SSL Configuration

Nginx is one of the most popular web servers, known for performance and simplicity.

Basic SSL Configuration

File structure:

/etc/ssl/certs/
├── example.com.crt       # Server certificate
├── intermediate.crt      # Intermediate CA
└── fullchain.pem         # Combined (cert + intermediate)

/etc/ssl/private/
└── example.com.key       # Private key (keep secure!)

Option 1: Using fullchain.pem (Recommended)

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;

    # SSL certificate and key
    ssl_certificate     /etc/ssl/certs/fullchain.pem;
    ssl_certificate_key /etc/ssl/private/example.com.key;

    # SSL session settings
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # Modern SSL configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # HSTS (optional but recommended)
    add_header Strict-Transport-Security "max-age=63072000" always;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;

    root /var/www/example.com;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

# HTTP to HTTPS redirect
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    
    return 301 https://$host$request_uri;
}

Option 2: Separate certificate and chain

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate     /etc/ssl/certs/example.com.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;
    
    # Optional: Explicitly specify intermediate certificates
    # Nginx will read and include them automatically from ssl_certificate
    # if it contains the full chain
    
    # ... rest of configuration
}

Creating fullchain.pem

If you have separate files:

# Concatenate server cert + intermediate cert(s)
cat example.com.crt intermediate.crt > fullchain.pem

# Or with multiple intermediates
cat example.com.crt intermediate1.crt intermediate2.crt > fullchain.pem

# Verify the chain
openssl verify -CAfile root.crt -untrusted intermediate.crt example.com.crt

Let’s Encrypt with Certbot

# Install certbot
sudo apt-get install certbot python3-certbot-nginx

# Obtain certificate
sudo certbot --nginx -d example.com -d www.example.com

# Certbot automatically configures Nginx and creates:
# /etc/letsencrypt/live/example.com/fullchain.pem
# /etc/letsencrypt/live/example.com/privkey.pem

Testing Nginx Configuration

# Test configuration syntax
sudo nginx -t

# Reload Nginx
sudo systemctl reload nginx

# Check SSL configuration
openssl s_client -connect example.com:443 -servername example.com

# Verify certificate chain
openssl s_client -connect example.com:443 -showcerts

Apache SSL Configuration

Apache is another widely-used web server with powerful SSL capabilities.

Basic SSL Configuration

Enable SSL module:

# Debian/Ubuntu
sudo a2enmod ssl
sudo a2enmod headers
sudo systemctl restart apache2

File structure:

/etc/ssl/certs/
├── example.com.crt       # Server certificate
├── intermediate.crt      # Intermediate CA bundle
└── ca-bundle.crt         # Alternative name

/etc/ssl/private/
└── example.com.key       # Private key

Virtual Host Configuration (/etc/apache2/sites-available/example.com-ssl.conf):

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    
    DocumentRoot /var/www/example.com

    # SSL Engine
    SSLEngine on
    
    # Certificate files
    SSLCertificateFile      /etc/ssl/certs/example.com.crt
    SSLCertificateKeyFile   /etc/ssl/private/example.com.key
    SSLCertificateChainFile /etc/ssl/certs/intermediate.crt
    
    # For Apache 2.4.8+, use SSLCACertificateFile instead of SSLCertificateChainFile
    # SSLCACertificateFile   /etc/ssl/certs/intermediate.crt

    # SSL Protocol and Cipher settings
    SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
    SSLHonorCipherOrder     off
    SSLCompression          off
    SSLSessionTickets       off

    # HSTS (optional but recommended)
    Header always set Strict-Transport-Security "max-age=63072000"
    
    # Security headers
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-XSS-Protection "1; mode=block"

    # Logging
    ErrorLog ${APACHE_LOG_DIR}/example.com-ssl-error.log
    CustomLog ${APACHE_LOG_DIR}/example.com-ssl-access.log combined
</VirtualHost>

# HTTP to HTTPS redirect
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    
    Redirect permanent / https://example.com/
</VirtualHost>

Apache with fullchain.pem

If you have a fullchain.pem file:

<VirtualHost *:443>
    ServerName example.com
    
    SSLEngine on
    
    # Use fullchain for both certificate and chain
    SSLCertificateFile      /etc/ssl/certs/fullchain.pem
    SSLCertificateKeyFile   /etc/ssl/private/example.com.key
    
    # SSLCertificateChainFile not needed with fullchain
    
    # ... rest of configuration
</VirtualHost>

Enable Site and Reload

# Enable SSL site
sudo a2ensite example.com-ssl.conf

# Test configuration
sudo apache2ctl configtest

# Reload Apache
sudo systemctl reload apache2

# Check SSL
openssl s_client -connect example.com:443 -servername example.com

Windows IIS SSL Configuration

IIS (Internet Information Services) is the web server for Windows environments.

Prerequisites

  • Certificate in .pfx format (includes private key)
  • Administrative access to IIS

Method 1: IIS Manager GUI

  1. Import Certificate:

    • Open IIS Manager
    • Click on server name in left panel
    • Double-click “Server Certificates”
    • Click “Import…” in right panel
    • Browse to .pfx file
    • Enter password
    • Click OK
  2. Bind Certificate to Site:

    • Expand “Sites” in left panel
    • Right-click your site → “Edit Bindings…”
    • Click “Add…”
    • Select “Type: https”
    • Port: 443
    • Select SSL certificate from dropdown
    • Click OK
  3. Configure HTTPS Redirect (optional):

    • Select your site
    • Double-click “URL Rewrite” (install if not present)
    • Add rule to redirect HTTP to HTTPS

Method 2: PowerShell

# Import certificate
$certPassword = ConvertTo-SecureString -String "YourPassword" -Force -AsPlainText
Import-PfxCertificate -FilePath "C:\Certs\example.com.pfx" `
    -CertStoreLocation Cert:\LocalMachine\My `
    -Password $certPassword

# Get certificate thumbprint
$cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Subject -like "*example.com*"}
$thumbprint = $cert.Thumbprint

# Bind certificate to site
New-WebBinding -Name "Default Web Site" -Protocol "https" -Port 443
$binding = Get-WebBinding -Name "Default Web Site" -Protocol "https" -Port 443
$binding.AddSslCertificate($thumbprint, "my")

# Force HTTPS redirect (if URL Rewrite is installed)
Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
    -filter "system.webServer/rewrite/rules" `
    -name "." `
    -value @{name='HTTP to HTTPS'; stopProcessing='True'}

Converting Certificates for IIS

If you have PEM files, convert to PFX:

# Linux/Mac
openssl pkcs12 -export -out certificate.pfx \
    -inkey private.key \
    -in certificate.crt \
    -certfile ca-bundle.crt

# Then transfer .pfx to Windows server

PowerShell (Windows with OpenSSL):

& "C:\Program Files\OpenSSL\bin\openssl.exe" pkcs12 -export `
    -out certificate.pfx `
    -inkey private.key `
    -in certificate.crt `
    -certfile ca-bundle.crt

IIS-Specific Considerations

  1. Certificate Store: IIS uses Windows Certificate Store
  2. Private Key Permissions: Ensure IIS App Pool identity has read access
  3. SNI (Server Name Indication): Enable for multiple SSL sites on same IP
  4. Intermediate Certificates: Automatically included from Windows Certificate Store

Verifying SSL Installation

Online Tools

Command Line Testing

# Basic SSL connection test
openssl s_client -connect example.com:443 -servername example.com

# Check certificate expiration
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates

# Verify certificate chain
openssl s_client -connect example.com:443 -showcerts

# Check specific protocol version
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3

Using curl

# Test HTTPS connection
curl -I https://example.com

# Show certificate details
curl -vI https://example.com

# Test certificate validation
curl --insecure https://example.com  # Should show certificate error if invalid

Common Issues and Solutions

Issue: “Certificate chain incomplete”

Symptoms:

  • Browser warnings on some devices
  • Mobile devices can’t connect
  • SSL Labs shows “Chain issues”

Solution:

# Ensure intermediate certificates are included
# Nginx: Use fullchain.pem
cat example.com.crt intermediate.crt > fullchain.pem

# Apache: Specify SSLCertificateChainFile
SSLCertificateChainFile /etc/ssl/certs/intermediate.crt

Issue: “NET::ERR_CERT_COMMON_NAME_INVALID”

Symptoms:

  • Certificate valid but browser shows warning
  • Name in certificate doesn’t match domain

Solution:

  • Verify certificate CN (Common Name) matches domain
  • Check Subject Alternative Names (SAN) include all domains
  • Ensure www and non-www variants are covered

Issue: “SSL handshake failed”

Symptoms:

  • Cannot establish SSL connection
  • Timeout errors

Solution:

# Check certificate and key match
openssl x509 -noout -modulus -in certificate.crt | openssl md5
openssl rsa -noout -modulus -in private.key | openssl md5
# MD5 hashes should match

# Verify private key is valid
openssl rsa -in private.key -check

# Check certificate is valid
openssl x509 -in certificate.crt -text -noout

Issue: “Mixed content warnings”

Symptoms:

  • Page loads but shows “Not Secure”
  • Some resources loaded over HTTP

Solution:

  • Update all internal links to use HTTPS or relative URLs
  • Configure Content Security Policy
  • Use HSTS to enforce HTTPS

Best Practices

  1. Use Strong Cipher Suites

    • TLS 1.2 and 1.3 only
    • Disable SSLv3, TLS 1.0, TLS 1.1
    • Use modern cipher suites
  2. Enable HSTS

    Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
    
  3. Include Complete Certificate Chain

    • Always include intermediate certificates
    • Test on multiple browsers/devices
  4. Regular Certificate Monitoring

    • Track expiration dates
    • Set up renewal reminders
    • Use tools like CrtMgr
  5. Secure Private Keys

    • Restrict file permissions (chmod 600)
    • Never commit to version control
    • Use strong passphrases
  6. Automate Renewal

    • Use Let’s Encrypt with automatic renewal
    • Set up monitoring for expiring certificates
    • Test renewal process
  7. Test Thoroughly

    • SSL Labs scan
    • Multiple browsers
    • Mobile devices
    • Certificate chain verification

Automation and Monitoring

Certbot (Let’s Encrypt)

# Auto-renewal test
sudo certbot renew --dry-run

# Set up automatic renewal (systemd)
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer

Certificate Monitoring

Use CrtMgr to:

  • Monitor certificate expiration
  • Get renewal alerts
  • Track multiple domains
  • Download certificates in any format
  • Public certificate viewing

Deployment Automation

# Example deployment script
#!/bin/bash
DOMAIN="example.com"
CERT_PATH="/etc/letsencrypt/live/$DOMAIN"

# Obtain/renew certificate
certbot certonly --webroot -w /var/www/$DOMAIN -d $DOMAIN -d www.$DOMAIN

# Copy to nginx location
cp $CERT_PATH/fullchain.pem /etc/nginx/ssl/$DOMAIN.crt
cp $CERT_PATH/privkey.pem /etc/nginx/ssl/$DOMAIN.key

# Reload nginx
nginx -t && systemctl reload nginx

Conclusion

Proper SSL/TLS certificate deployment requires understanding certificate chains, server-specific configuration, and security best practices. Key takeaways:

  • Always include intermediate certificates for complete chain of trust
  • Use fullchain.pem for Nginx (simplest approach)
  • Configure strong cipher suites and disable old protocols
  • Enable HSTS for enhanced security
  • Monitor expiration dates and automate renewal
  • Test thoroughly with SSL Labs and multiple devices

Need help managing and monitoring your certificates? Try CrtMgr for automated certificate tracking, expiration alerts, and easy deployment!

Related Articles