An SSL/TLS certificate encrypts the traffic between your website and visitors' browsers, authenticates your domain identity, and is a non-negotiable requirement for the modern web. Google Chrome has marked non-HTTPS sites as Not Secure since 2018; Search Console treats HTTPS as a ranking signal; PCI-DSS demands TLS 1.2+ for any site that processes payment cards. This guide walks you through what an SSL certificate is, which type to choose, where to buy free or paid certificates, how to install them on Nginx/Apache/cPanel/Plesk, and how to set up automated renewal and security hardening — all from a production sysadmin's perspective.

SSL vs TLS: A Quick Refresher

Related guides: OWASP Top 10 2026 · JWT security · SQL injection prevention · Password hashing guide · DDoS protection

SSL (Secure Sockets Layer), originally designed by Netscape in 1995, has been entirely superseded by TLS (Transport Layer Security). The industry still says "SSL certificate" out of habit, but what you actually buy is an X.509 TLS certificate (RFC 5280). TLS 1.0 and 1.1 were officially deprecated by the IETF in 2021; the only versions you should support today are TLS 1.2 and TLS 1.3.

TLS 1.3 (RFC 8446) brings three major improvements over TLS 1.2: removal of weak cipher suites (RC4, 3DES, CBC mode), a 1-RTT handshake (half the latency of 1.2's 2-RTT), and optional 0-RTT resumption (zero-latency, but with replay-attack caveats — use with care). Always enable TLS 1.3 on modern stacks and keep TLS 1.2 around for backward compatibility.

The Certificate Chain and Public-Key Crypto

A TLS certificate never works alone; it forms a root → intermediate → leaf chain of trust. Browsers only trust root certificates that ship in their OS or browser trust store (Mozilla CA Program, Microsoft Trusted Root, Apple Trust Store, Chrome Root Store). Your server must serve fullchain.pem (leaf + intermediate concatenated) — otherwise Android devices will throw "NET::ERR_CERT_AUTHORITY_INVALID".

Issuance starts with a private key and a CSR (Certificate Signing Request) generated from it. The private key stays on the server and is never shared; the CSR is a signed request containing your public key and domain details, which the CA signs to produce the certificate. Rules CAs must follow are defined in the CA/Browser Forum Baseline Requirements.

Certificate Types: DV, OV, EV, Wildcard, SAN

DV (Domain Validation): Fastest and most common. The CA only verifies domain control (HTTP-01, DNS-01, or TLS-ALPN-01 challenge). Issuance takes minutes, free options exist (Let's Encrypt, ZeroSSL, Buypass), and DV is sufficient for blogs, SaaS apps, and corporate brochure sites.

OV (Organization Validation): The CA also verifies the organization's name, address, and phone number against D&B records or government registries. The cert's Subject field contains the company info, visible in browser certificate details. Issuance takes 1-3 business days; pricing is 50-150 USD/year. A reasonable middle ground for B2B SaaS, fintech, and enterprise vendors.

EV (Extended Validation): The strictest validation — legal entity verification, physical address, phone confirmation, signed authorization. Browsers used to render the URL bar with a green company-name pill; Chrome 77 (2019) and Firefox 70 removed this UI signal. EV's practical UX benefit is essentially gone, but banks, airlines, and listed companies still procure EV due to vendor or compliance policy.

Wildcard (*.example.com): Covers all first-level subdomains with a single cert (api.example.com, blog.example.com, mail.example.com). Multi-level subdomains (a.b.example.com) are not covered. Let's Encrypt issues wildcards but only via DNS-01 — HTTP-01 cannot validate a wildcard.

Multi-Domain / SAN (Subject Alternative Names): A single cert listing up to ~100 different hostnames. Ideal for agencies running multiple brands on the same infrastructure; reduces installation and renewal overhead.

Free or Paid? A Practical Decision Matrix

Let's Encrypt covers 95% of use cases. Run by the non-profit Internet Security Research Group (ISRG), Let's Encrypt issues 90-day DV certs over the ACME protocol. Tools like certbot, acme.sh, and panel integrations renew automatically. Buypass Go SSL issues 180-day free certs as an alternative; ZeroSSL stands out with a friendlier GUI and REST API. All three are 100% trusted by browsers.

Pay for a commercial cert when you have one of these requirements:

  • OV/EV trust signal: Banking, payments, healthcare, enterprise portals — contractual or regulatory
  • Warranty: Sectigo 10K-2M USD, DigiCert up to 1.75M USD — financial protection if the CA mis-issues
  • 24/7 phone support: Available on enterprise CA accounts
  • Legacy device / IoT compatibility: Java 7, old Android, payment terminals may have different root stores
  • Code-signing or S/MIME: Let's Encrypt only issues TLS server certs; code signing and email signing require a paid CA

Where to Buy Paid Certificates

Sectigo (formerly Comodo CA) has the largest commercial CA market share globally, with budget-friendly pricing and a wide reseller network. DigiCert leads the enterprise segment with high warranty values and fast OV/EV issuance; it acquired Symantec, GeoTrust, Thawte, and RapidSSL in 2017. GlobalSign is strong in the European market and offers eIDAS-compliant qualified certificates.

You can buy the same certs much cheaper through resellers: Namecheap, SSLs.com, GoGetSSL, The SSL Store are common picks. KEYDAL hosting plans include free Let's Encrypt integration plus paid OV/EV procurement and installation support for enterprise needs — see /services.

Let's Encrypt + Certbot: The Fastest Path

On Ubuntu/Debian with Nginx, the shortest path to HTTPS is Certbot. Certbot (by the EFF) auto-edits your server config, fetches the cert, and wires up renewal via cron or a systemd timer.

# Ubuntu/Debian — install Certbot and obtain a cert via Nginx
sudo apt update
sudo apt install -y certbot python3-certbot-nginx

# One-shot: edit Nginx config + issue cert
sudo certbot --nginx \
    -d example.com -d www.example.com \
    --email admin@example.com --agree-tos --no-eff-email --redirect

# Test renewal (no real request to ACME servers)
sudo certbot renew --dry-run

# List installed certs
sudo certbot certificates

After installation, Certbot's systemd timer (systemctl list-timers | grep certbot) runs twice a day by default and renews when the cert is within 30 days of expiry. For Apache, install python3-certbot-apache and use the --apache flag instead.

acme.sh: Lightweight, Rootless

acme.sh is a pure shell ACME client with no Python dependency, runnable as a non-root user. It's much more practical than Certbot on shared hosting, BSD systems, and slim container images, and ships with 150+ DNS provider integrations (Cloudflare, Route 53, GoDaddy, NameCheap).

# Install acme.sh as a non-root user
curl https://get.acme.sh | sh -s email=admin@example.com
source ~/.bashrc

# Issue cert via HTTP-01 (webroot)
acme.sh --issue -d example.com -d www.example.com \
    --webroot /var/www/html

# Install cert and reload Nginx
acme.sh --install-cert -d example.com \
    --fullchain-file /etc/ssl/example.com/fullchain.pem \
    --key-file       /etc/ssl/example.com/key.pem \
    --reloadcmd      "systemctl reload nginx"

# Wildcard via DNS-01 (Cloudflare example)
export CF_Token="..."
export CF_Account_ID="..."
acme.sh --issue --dns dns_cf -d example.com -d '*.example.com'

acme.sh adds a daily cron entry during installation, so you don't need to schedule renewals manually. The default CA is ZeroSSL; switch to Let's Encrypt with acme.sh --set-default-ca --server letsencrypt.

Panel-Driven Installation: cPanel, Plesk, DirectAdmin, CyberPanel

cPanel AutoSSL: Under WHM > SSL/TLS > Manage AutoSSL, choose Sectigo or Let's Encrypt as the provider; cPanel auto-issues and renews certs for every hosting account. WHM > Manage Account > Manage AutoSSL lets you exclude specific domains.

Plesk: On the domain detail page, tick SSL/TLS Certificates > Install a free basic certificate provided by Let's Encrypt. Include the mail subdomain (mail.domain.com), webmail, and www. Plesk Onyx and later support DNS-01 challenge, enabling wildcard issuance from the panel.

DirectAdmin: User Level > SSL Certificates > "Free & automatic certificate from Let's Encrypt". The panel auto-creates the .well-known directory under DocumentRoot. Hosting plan admin must enable letsencrypt=ON first.

CyberPanel + LiteSpeed: Click "Issue SSL" under the SSL menu — issued and auto-renewed in a single click. For containerized stacks use Caddy (built-in automatic TLS) or Traefik (Let's Encrypt resolver).

# Traefik v2 — automatic Let's Encrypt TLS (docker-compose.yml)
services:
  traefik:
    image: traefik:v2.11
    command:
      - --providers.docker=true
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --certificatesresolvers.le.acme.email=admin@example.com
      - --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.le.acme.tlschallenge=true
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./letsencrypt:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock:ro
  app:
    image: nginx:alpine
    labels:
      - traefik.enable=true
      - traefik.http.routers.app.rule=Host(`example.com`)
      - traefik.http.routers.app.entrypoints=websecure
      - traefik.http.routers.app.tls.certresolver=le

Manual CSR Generation (for Paid Certs)

When buying from a commercial CA you'll need to submit a CSR generated by OpenSSL. RSA 2048-bit is the industry standard; ECDSA P-256 is smaller and faster, supported by all modern browsers. Use RSA if you must support legacy Android 4.x or Windows XP clients.

# RSA 2048-bit private key + CSR (subject inline)
openssl req -newkey rsa:2048 -nodes \
    -keyout /etc/ssl/private/example.com.key \
    -out    /etc/ssl/certs/example.com.csr \
    -subj "/C=TR/ST=Istanbul/L=Istanbul/O=KEYDAL/OU=IT/CN=example.com"

# ECDSA P-256 (smaller, faster)
openssl ecparam -genkey -name prime256v1 -out example.com.key
openssl req -new -key example.com.key -out example.com.csr \
    -subj "/C=TR/ST=Istanbul/O=KEYDAL/CN=example.com"

# Verify CSR contents before sending to the CA
openssl req -in example.com.csr -noout -text | grep -E 'Subject:|DNS:'

# CSR with SANs requires a config file
cat > csr.cnf <<'EOF'
[req]
distinguished_name = req
req_extensions = v3_req
prompt = no
[req]
C = TR
O = KEYDAL
CN = example.com
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = api.example.com
EOF
openssl req -new -key example.com.key -out example.com.csr -config csr.cnf

The CA usually returns two files: example.com.crt (leaf) and intermediate.crt. Concatenate them before serving: cat example.com.crt intermediate.crt > fullchain.pem. A missing intermediate breaks Android devices and old Java clients; SSL Labs will report "Chain issues: Incomplete".

Modern Nginx TLS Config (Mozilla Intermediate)

The config below is based on the "Intermediate" profile from the Mozilla SSL Configuration Generator: 95%+ browser compatibility and an A+ on SSL Labs. If you only need to support recent browsers, switch to the "Modern" profile (TLS 1.3 only).

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

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

    # Mozilla Intermediate — TLS 1.2 + 1.3
    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;

    # Session — for performance
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # OCSP stapling — clients don't fetch revocation status
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 8.8.8.8 valid=300s;
    resolver_timeout 5s;

    # HSTS — preload eligible (start with shorter max-age, then ramp up)
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

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

Apache 2.4 SSL VirtualHost

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

    SSLEngine on
    SSLCertificateFile      /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile   /etc/letsencrypt/live/example.com/privkey.pem

    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
    SSLHonorCipherOrder     off
    SSLSessionTickets       off

    SSLUseStapling          on
    SSLStaplingCache        "shmcb:logs/ssl_stapling(32768)"

    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
</VirtualHost>
</IfModule>

<VirtualHost *:80>
    ServerName example.com
    Redirect permanent / https://example.com/
</VirtualHost>

CAA DNS Record: Lock Down Who Can Issue

A CAA (Certification Authority Authorization) record restricts which CAs are allowed to issue certificates for your domain. If an attacker tries to obtain a cert for your domain from a different CA, that CA must check the CAA record and refuse. CA/Browser Forum has required CAA enforcement since 2017.

; example.com — only Let's Encrypt may issue
example.com.    IN  CAA  0 issue "letsencrypt.org"
example.com.    IN  CAA  0 issuewild "letsencrypt.org"
example.com.    IN  CAA  0 iodef "mailto:security@example.com"

; Allow multiple CAs
example.com.    IN  CAA  0 issue "sectigo.com"
example.com.    IN  CAA  0 issue "digicert.com"

Verify with dig example.com CAA +short. Cloudflare, Route 53, and Hetzner DNS all support CAA. If your registrar does not, move DNS hosting to a free provider like Cloudflare.

HSTS and HSTS Preload

HSTS (HTTP Strict Transport Security) tells the browser "only visit this domain over HTTPS for the next N seconds". It's a critical defense against SSL stripping and Wi-Fi MITM attacks. See the MDN HSTS reference.

# Test phase — short max-age
Strict-Transport-Security: max-age=300

# Production — 1 year
Strict-Transport-Security: max-age=31536000

# Force on subdomains too
Strict-Transport-Security: max-age=31536000; includeSubDomains

# Preload list minimum requirements
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

Submit your domain at hstspreload.org to ship inside the browser's built-in HSTS list — preloaded domains are forced to HTTPS even on first visit. Warning: removal from the list takes weeks; make sure every subdomain is fully HTTPS-ready before submitting.

OCSP Stapling: Revocation Without the Round-Trip

OCSP (Online Certificate Status Protocol) checks whether a certificate has been revoked. In the classic flow, the browser contacts the CA's OCSP responder on every page load — slow and a privacy leak (the CA learns which sites you visit). With OCSP Stapling, the server fetches the OCSP response periodically and includes it in the TLS handshake; the client never contacts the CA.

In Nginx, ssl_stapling on; ssl_stapling_verify on; is enough (already in the config above). Verify with openssl s_client -connect example.com:443 -status and look for OCSP Response Status: successful.

Certificate Transparency: Watch for Rogue Certs

Certificate Transparency (CT) requires every CA to log every issued cert to a public append-only log. Chrome and Safari refuse certificates that aren't in the CT logs. CT lets you detect unauthorized certs issued for your domain quickly.

Search your domain on crt.sh to see every cert ever issued for it. Set up email alerts via Facebook CT Monitoring or Cert Spotter: any new cert issuance triggers a notification — an unexpected entry is a signal worth investigating.

Testing and Scoring: Aim for SSL Labs A+

The industry standard verification tool is Qualys SSL Labs SSL Test. To score A+ you need TLS 1.3 support, HSTS preload, complete chain, strong cipher selection, and OCSP stapling. Use the commands below for quick checks from the shell.

# Cert and chain details
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates

# Confirm TLS 1.3 support
openssl s_client -connect example.com:443 -tls1_3 </dev/null 2>&1 | grep 'Protocol\|Cipher'

# Verify chain is complete
echo | openssl s_client -connect example.com:443 -showcerts 2>/dev/null | grep -c 'BEGIN CERTIFICATE'

# Quick curl check
curl -vI https://example.com 2>&1 | grep -E 'SSL connection|subject|issuer|HTTP/'

# Comprehensive — testssl.sh
docker run --rm -ti drwetter/testssl.sh https://example.com

testssl.sh is open-source and runs against private servers too; many shops wire it into CI to run TLS regression tests after every deploy. Mozilla's Observatory grades HTTP headers, TLS, and content security in one report.

Automated Renewal: Don't Let Certs Expire

Expired TLS certificates are one of the most common causes of avoidable downtime on modern web infrastructure. Microsoft Teams (2022), LinkedIn (2017), Cisco WebEx (2020), and PagerDuty (2018) all had multi-hour outages from forgotten cert renewals. Automation is mandatory.

  • Certbot: certbot.timer is auto-installed on Ubuntu/Debian, runs twice daily
  • acme.sh: Adds a daily cron entry on install
  • cPanel AutoSSL: Auto from WHM, daily
  • Plesk: Renews 60 days before expiry
  • Manual certs: Calendar reminder + Uptime Kuma cert-expiry monitor
  • Kubernetes: Use cert-manager with a Let's Encrypt or ZeroSSL Issuer

Track cert expiry with UptimeRobot, Uptime Kuma, or a custom cron script — alert at 14 days before expiry.

Common Pitfalls and Fixes

Mixed Content: An HTTPS page loading HTTP resources (img, script, iframe) triggers browser warnings. Fix: rewrite all internal links to protocol-relative (//) or https://; add upgrade-insecure-requests to your CSP header.

Missing Intermediate: Serving only cert.pem instead of fullchain.pem — breaks Android and old Java clients. Always use fullchain.pem. Verify on SSL Labs: look for the "Chain issues" line.

Hostname Mismatch: Cert issued for example.com but the site runs on www.example.com. Fix: include both names in the SAN list (-d example.com -d www.example.com) or buy a wildcard.

Let's Encrypt Rate Limits: 50 certs per registered domain per week; 5 duplicate certs for the same SAN set per week; 5 failed validations per account per hour. Use the staging environment (--staging flag) when testing.

Wildcard + HTTP-01: Doesn't work. Wildcards require DNS-01 — your DNS provider must allow programmatic TXT record creation. Cloudflare, Route 53, and Hetzner DNS APIs integrate cleanly with Certbot/acme.sh.

Cron Not Actually Running: Renewal automation believed to be in place but the cert silently expires — extremely common. Log the renewal output and audit weekly: certbot renew --post-hook "systemctl reload nginx" && logger -t certbot 'renew ok'.

PCI-DSS, GDPR, and Regulatory Considerations

E-commerce or any site processing card data must comply with PCI-DSS 3.1+, which fully bans TLS 1.0 and 1.1; minimum TLS 1.2 is mandatory. Under GDPR, transmitting personal data over an unencrypted channel is a clear breach of "appropriate technical measures". web.dev — Why HTTPS Matters summarizes the broader rationale.

For high-security environments add: TLS 1.3 only, AEAD-only ciphers (GCM/CHACHA20), CAA + CT monitoring (HPKP is deprecated), ECDSA P-256 keys, mTLS (client cert) on admin panels, and an independent penetration test report.

Quick Checklist

  • I serve fullchain.pem, no missing intermediate
  • TLS 1.2 and 1.3 enabled, older versions disabled
  • HSTS header set to 1 year with includeSubDomains
  • CAA record present in DNS
  • OCSP stapling enabled
  • Automated renewal cron/timer is actually running
  • SSL Labs A+ (or at least A)
  • No mixed content; CSP has upgrade-insecure-requests
  • Alert configured 30 days before cert expiry
  • Weekly crt.sh review for unauthorized issuance

Web Security and Application Defense

Modern web security uses defense-in-depth: TLS 1.3 and HSTS for encrypted transport, WAF (Web Application Firewall) against OWASP Top 10, BCrypt or Argon2id for password hashing, JWT tokens with proper signature verification (HMAC or RSA), CSRF tokens with SameSite cookies and Content Security Policy to mitigate XSS. Prepared statements prevent SQL injection, fail2ban or rate limiting blocks brute force, and DDoS protection via Cloudflare or anti-DDoS providers is essential. Vulnerability scanning (Burp Suite, OWASP ZAP) and regular security audits significantly reduce data leak and account takeover risks in production.

Sources

Get expert help with your SSL setup

Let's Encrypt automation, paid OV/EV procurement, A+ hardening, HSTS preload submission, and certificate monitoring — contact us

WhatsApp