SSL/TLS Certificates: Complete Understanding¶
Table of Contents¶
- The Fundamental Problem
- What is an SSL/TLS Certificate?
- Types of Certificates
- Certificate Files Explained
- Certificate Authorities
- All Methods to Get Certificates
- Manual Certificate Generation
- Let's Encrypt vs ZeroSSL vs Commercial CAs
- Using Certificates in Different Services
- Understanding the Certificate Chain
The Fundamental Problem¶
Without HTTPS (Plain HTTP)¶
Your Browser → http://jenkins.ibtisam-iq.com
↓
Data travels in PLAIN TEXT
↓
Anyone in the middle can:
- Read your passwords
- See all data
- Modify requests
Problem: Data travels unencrypted - anyone can intercept and read it!
With HTTPS (HTTP + SSL/TLS)¶
Your Browser → https://jenkins.ibtisam-iq.com
↓
Data is ENCRYPTED
↓
Middle person sees: ���1j#@k!x8%^
Cannot read or modify!
Solution: Data is encrypted end-to-end - only browser and server can decrypt it!
What is an SSL/TLS Certificate?¶
Real-World Analogy¶
Certificate = Passport or Government ID
Your Passport contains:
- Your name
- Your photo
- Issued by: Government
- Expiry date
- Government's signature
SSL Certificate contains:
- Domain name (jenkins.ibtisam-iq.com)
- Public key
- Issued by: Certificate Authority
- Expiry date
- CA's digital signature
Key Point: Just like a passport proves your identity, an SSL certificate proves a website's identity.
What Certificate Does¶
Two main functions:
- Encryption - Encrypts data so no one can read it in transit
- Authentication - Proves you're talking to the legitimate website, not an imposter
Types of Certificates¶
1. Self-Signed Certificate¶
Who signs it? You sign it yourself
Analogy: Creating your own ID card without government verification - anyone can claim to be anyone!
How it works:
You create certificate
You sign it with your own private key
You say: "Trust me, I am jenkins.ibtisam-iq.com"
Browser's response:
⚠️ "Not Secure"
⚠️ "Your connection is not private"
⚠️ NET::ERR_CERT_AUTHORITY_INVALID
Why browser doesn't trust it? - Anyone can create self-signed certificates - No third-party verification - Could be an attacker pretending to be the legitimate site - No way to verify authenticity
When to use: - ✅ Development and testing environments - ✅ Internal company networks (where you control all clients) - ✅ localhost testing - ✅ Learning and experimentation - ❌ NEVER for public-facing websites
Pros: - Free - No external dependencies - Full control - Instant creation
Cons: - Browser warnings scare users - No trust from third parties - Manual trust configuration needed on all clients - Not suitable for production
2. CA-Signed Certificate (Trusted)¶
Who signs it? Trusted Certificate Authority (CA)
Analogy: Government-issued passport - universally trusted because a recognized authority verified your identity!
How it works:
You generate Certificate Signing Request (CSR)
Send CSR to CA (Let's Encrypt, ZeroSSL, etc.)
CA verifies: "Yes, you control jenkins.ibtisam-iq.com"
CA signs your certificate with THEIR private key
Browser trusts CA → Browser trusts your certificate
Browser's response:
✅ 🔒 Secure
✅ No warnings
✅ Green padlock icon
Why browser trusts it?
- CA is pre-trusted by browser (built into trust store)
- CA performed domain ownership verification
- CA's digital signature acts as proof of legitimacy
- Chain of trust leads to trusted root CA
Types based on validation level:
| Type | Validation | Time to Issue | Use Case | Cost |
|---|---|---|---|---|
| DV (Domain Validated) | Domain ownership only | Minutes | Personal blogs, basic websites | Free-$100/yr |
| OV (Organization Validated) | Domain + company verification | 1-3 days | Business websites | \(50-\)300/yr |
| EV (Extended Validation) | Domain + legal entity + physical address | 1-2 weeks | Banks, e-commerce, high-trust sites | \(200-\)1000/yr |
DV Certificate:
- Verifies you control the domain
- No company verification
- Fastest to get
- Good for most use cases
OV Certificate:
- Verifies domain ownership
- Verifies company is real and registered
- Shows organization name in certificate
- Better for corporate sites
EV Certificate:
- Most rigorous verification
- Legal entity verification required
- Physical address verification
- Historically showed company name in green bar (removed in modern browsers)
- Highest trust level for financial/sensitive sites
Certificate Files Explained¶
When working with SSL certificates, you'll encounter various files. Understanding each one is critical.
The Files You'll See¶
1. Private Key (.key, privkey.pem)¶
What is it?
Secret key used for decryption
NEVER share with anyone
Used to decrypt incoming encrypted data
If compromised, attacker can decrypt all traffic
File format:
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7...
(Base64 encoded binary data - appears as random characters)
...
-----END PRIVATE KEY-----
Critical security points:
- Keep this file absolutely secret
- Store in restricted directory (permissions 600 or 400)
- Never commit to version control
- Never send via email or unsecured channels
- If lost, you must regenerate entire certificate
- If stolen, attacker can:
- Decrypt your HTTPS traffic
- Impersonate your website
- Sign malicious content
Analogy: Your house's master key - anyone with it can unlock everything!
Typical location:
/etc/ssl/private/(Linux)/etc/letsencrypt/live/domain/privkey.pem(Let's Encrypt)
2. Certificate Signing Request (.csr)¶
What is it?
Request file you submit to Certificate Authority
Contains domain name, organization info, and public key
Does NOT contain private key (safe to share)
One-time use - discard after receiving signed certificate
File format:
-----BEGIN CERTIFICATE REQUEST-----
MIICvDCCAaQCAQAwdzELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0...
-----END CERTIFICATE REQUEST-----
What it contains:
- Common Name (CN): jenkins.ibtisam-iq.com
- Organization (O): Your Company Name
- Country (C): PK
- State/Province (ST): Punjab
- Locality (L): Rawalpindi
- Public Key: Cryptographic public key
- Your Signature: Proves you generated this request
Analogy: Passport application form you submit to government office - contains your information but not your actual passport yet.
When you need it:
- Manual certificate requests to commercial CAs
- ZeroSSL web interface
- Corporate certificate management
- Not needed for automated tools like Certbot
3. Public Certificate (.crt, .cert, cert.pem)¶
What is it?
Your actual signed certificate
Contains your domain and public key
Signed by Certificate Authority
Safe to share publicly (given to all clients)
File format:
-----BEGIN CERTIFICATE-----
MIIFjTCCBHWgAwIBAgISA1234567890abcdefghijklmnopqr...
(Certificate data - readable with OpenSSL tools)
...
-----END CERTIFICATE-----
What it contains:
- Subject: jenkins.ibtisam-iq.com (your domain)
- Issuer: Let's Encrypt Authority X3 (who signed it)
- Public Key: Used for encryption
- Validity Period: Not Before / Not After dates
- Serial Number: Unique identifier
- Signature Algorithm: RSA, ECDSA, etc.
- CA's Digital Signature: Proof of authenticity
Analogy: Your actual issued passport - proves your identity to others.
View certificate contents:
openssl x509 -in cert.pem -text -noout
4. Certificate Chain (chain.pem, fullchain.pem)¶
What is it?
Complete trust chain from your certificate to root CA
Your certificate + all intermediate certificates
Required for browsers to verify trust path
Why needed? Browsers need complete path to verify trust:
Your Certificate
↓ signed by
Intermediate Certificate 1
↓ signed by
Intermediate Certificate 2
↓ signed by
Root Certificate (pre-installed in browser)
File format:
-----BEGIN CERTIFICATE-----
(Your certificate)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Intermediate certificate 1)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Intermediate certificate 2)
-----END CERTIFICATE-----
fullchain.pem vs chain.pem:
fullchain.pem= Your certificate + intermediates (use this for Nginx)chain.pem= Only intermediate certificates (without your cert)cert.pem= Only your certificate (without intermediates)
Common mistake:
# Wrong - only your certificate
ssl_certificate /path/to/cert.pem;
# Correct - certificate + intermediates
ssl_certificate /path/to/fullchain.pem;
Result of wrong configuration:
- Works in some browsers (Chrome caches intermediates)
- Fails in others (Firefox, curl, mobile browsers)
- Error: "Unable to verify certificate chain"
File Extensions Explained¶
Different extensions, often same content:
| Extension | Format | Description | Text/Binary | Common Use |
|---|---|---|---|---|
.pem | PEM | Base64 encoded, human readable | Text | Most common on Linux |
.crt | PEM/DER | Certificate only | Usually Text | Certificate file |
.cer | DER/PEM | Certificate only | Either | Windows/IIS |
.key | PEM | Private key | Text | Private key file |
.csr | PEM | Certificate signing request | Text | Sent to CA |
.pfx / .p12 | PKCS#12 | Bundle: cert + key + chain | Binary | Windows, Java, Jenkins |
.der | DER | Binary format | Binary | Java applications |
.p7b / .p7c | PKCS#7 | Certificate chain only (no key) | Binary | Windows, Tomcat |
PEM Format (most common):
- Text-based format
- Base64 encoded binary data
- Can open with any text editor
- Has BEGIN/END markers
- Can contain multiple items (cert, key, chain)
DER Format:
- Binary format
- Cannot read in text editor
- More compact than PEM
- Common in Windows and Java environments
PKCS#12 Format (.p12, .pfx):
- Password-protected bundle
- Contains private key + certificate + chain
- Binary format
- Used by Jenkins, Tomcat, Windows IIS
Converting between formats:
# PEM to DER
openssl x509 -in cert.pem -outform DER -out cert.der
# DER to PEM
openssl x509 -in cert.der -inform DER -out cert.pem
# PEM to PKCS#12 (for Jenkins)
openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out cert.p12
# PKCS#12 to PEM
openssl pkcs12 -in cert.p12 -out cert.pem -nodes
File Organization Best Practices¶
Typical Let's Encrypt structure:
/etc/letsencrypt/
├── live/
│ └── jenkins.ibtisam-iq.com/
│ ├── privkey.pem # Private key
│ ├── fullchain.pem # Certificate + chain
│ ├── cert.pem # Certificate only
│ └── chain.pem # Intermediate certs only
└── archive/
└── jenkins.ibtisam-iq.com/
├── privkey1.pem # Actual private key
├── fullchain1.pem # Actual full chain
└── ... # Numbered versions
Note: Files in live/ are symlinks to actual files in archive/
Manual certificate organization:
/etc/ssl/
├── private/ # Private keys (permissions 700)
│ └── jenkins.key # chmod 600
├── certs/ # Public certificates
│ ├── jenkins.crt
│ └── jenkins-fullchain.crt
└── csr/ # Certificate requests
└── jenkins.csr
Permissions:
# Private keys - only root can read
chmod 600 /etc/ssl/private/*.key
chown root:root /etc/ssl/private/*.key
# Certificates - readable by all
chmod 644 /etc/ssl/certs/*.crt
# Directories
chmod 700 /etc/ssl/private
chmod 755 /etc/ssl/certs
Certificate Authorities¶
What is a Certificate Authority (CA)?¶
Definition: A trusted third-party organization that verifies domain ownership and issues signed certificates.
Analogy: Government passport office - everyone trusts their verification process and signature.
What CAs do:
- Verify you own the domain
- Sign your certificate with their private key
- Maintain certificate revocation lists
- Provide validation infrastructure
- Ensure certificate standards compliance
How trust works:
- Browsers ship with pre-installed list of trusted root CAs
- Operating systems maintain trust stores
- When you visit HTTPS site, browser checks certificate chain
- If chain leads to trusted root CA, connection is trusted
- If chain is broken or leads to unknown CA, browser warns user
Popular Certificate Authorities¶
1. Let's Encrypt (Free, Automated)¶
Overview:
- Non-profit Certificate Authority
- Launched in 2016
- Completely free forever
- Automated certificate issuance and renewal
- Backed by major tech companies (Mozilla, Cisco, Google, AWS)
Features:
- ✅ 100% free
- ✅ Automated via ACME protocol
- ✅ Domain Validated (DV) certificates only
- ✅ Wildcard certificates supported
- ✅ 90-day validity (intentionally short for security)
- ✅ Automatic renewal via Certbot
- ❌ No Organization Validated (OV) certificates
- ❌ No Extended Validation (EV) certificates
- ❌ No commercial support (community only)
- ❌ Rate limits apply
Rate limits:
- 50 certificates per registered domain per week
- 5 duplicate certificates per week
- 300 new orders per account per 3 hours
- Usually not an issue for normal use
Best for:
- Personal websites and blogs
- Startups and small businesses
- Automated deployments
- Developers comfortable with CLI tools
- Any scenario where free is important
Not suitable for:
- Organizations requiring OV/EV validation
- Enterprises needing commercial support
- Situations requiring 1+ year validity
2. ZeroSSL (Free + Paid Tiers)¶
Overview:
- Commercial CA owned by Sectigo
- Offers free tier similar to Let's Encrypt
- Also has paid enterprise tiers
- Web-based dashboard available
Features:
- ✅ Free tier available (90-day DV certificates)
- ✅ Web dashboard for easier management
- ✅ Multiple verification methods (HTTP, DNS, CNAME, Email)
- ✅ REST API for automation
- ✅ Can generate certificates from browser
- ✅ Paid plans include Organization Validation
- ✅ Commercial support on paid tiers
- ⚠️ Free certificates require manual renewal
- ⚠️ Free tier has certificate limits
- ⚠️ API rate limits on free tier
Free vs Paid:
| Feature | Free | Paid |
|---|---|---|
| DV Certificates | 3 active | Unlimited |
| Validity | 90 days | 90 days - 1 year |
| Auto-renewal | No | Yes |
| Organization Validation | No | Yes |
| Support | Community | Email/Phone |
| API calls | Limited | Unlimited |
Best for:
- Users who prefer web interface over CLI
- Small teams managing multiple certificates manually
- Businesses that might need OV validation later
- Organizations wanting commercial support option
3. Commercial Certificate Authorities (Paid)¶
Major providers:
- DigiCert
- Sectigo (formerly Comodo)
- GlobalSign
- GoDaddy
- Entrust
- Thawte
Typical costs:
- DV: \(50-\)150/year
- OV: \(100-\)300/year
- EV: \(200-\)1,500/year
- Wildcard: \(200-\)500/year
Features:
- ✅ Organization Validation (OV)
- ✅ Extended Validation (EV)
- ✅ Longer validity periods (up to 1 year, limited by CAB Forum)
- ✅ Warranty/insurance (up to $1.75M coverage)
- ✅ 24/7 phone and email support
- ✅ Compliance certifications (SOC 2, WebTrust)
- ✅ Better for regulatory compliance (PCI-DSS, HIPAA)
- ✅ Account management tools
- ✅ Bulk purchase discounts
- ❌ Expensive
- ❌ Manual processes often involved
- ❌ Overkill for most use cases
When commercial CAs make sense:
- Enterprise environments with budget
- Organizations requiring OV/EV validation
- Compliance requirements (banking, healthcare, government)
- Need for warranty/insurance
- 24/7 support requirement
- Corporate policies mandate paid certificates
4. Internal/Private CAs¶
What: Run your own Certificate Authority
Use cases:
- Internal company networks
- Kubernetes clusters
- Microservices authentication
- Development environments
- IoT device management
Tools:
- OpenSSL (manual)
- CFSSL (CloudFlare's toolkit)
- Easy-RSA (used by OpenVPN)
- cert-manager (Kubernetes)
Pros:
- ✅ Full control
- ✅ No external dependencies
- ✅ No rate limits
- ✅ Custom certificate policies
- ✅ Any validity period you want
Cons:
- ❌ Not trusted by default (must distribute root CA to all clients)
- ❌ You manage entire infrastructure
- ❌ Security responsibility is yours
- ❌ Cannot use for public websites
Browser Trust Stores¶
How browsers know which CAs to trust:
Every browser/OS maintains a list of trusted root certificates:
Firefox:
- Uses own trust store (Mozilla Root Program)
- ~140 trusted root certificates
- Independent of OS
Chrome/Edge:
- Uses OS trust store on Windows/Mac
- Own store on Linux
- ~100-150 trusted roots
Safari:
- Uses macOS trust store
- Apple Root Certificate Program
Viewing trusted CAs:
# Linux - list system trusted CAs
ls /etc/ssl/certs/
# View specific CA
openssl x509 -in /etc/ssl/certs/ca-cert.pem -text -noout
# macOS - open Keychain Access
# Windows - certmgr.msc
CA must prove:
- Financial stability
- Technical competence
- Compliance with CAB Forum baseline requirements
- Proper security controls
- Annual audits (WebTrust)
CA can be removed if:
- Security incident (private key compromised)
- Mis-issuance of certificates
- Violation of baseline requirements
- Failed audits
Example: Symantec CA was distrusted by browsers in 2018 due to mis-issuance violations.
All Methods to Get Certificates¶
Method 1: Certbot (Let's Encrypt) - Fully Automated¶
What: Official ACME client for Let's Encrypt Automation Level: Fully automated Best For: Linux servers with public IP and root access
Installation:
# Ubuntu/Debian
sudo apt update
sudo apt install certbot python3-certbot-nginx -y
# CentOS/RHEL
sudo yum install certbot python3-certbot-nginx -y
# Using Snap (recommended)
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Get certificate - Nginx (fully automated):
sudo certbot --nginx -d jenkins.ibtisam-iq.com
What Certbot does automatically:
- Reads your Nginx configuration
- Finds server block matching domain
- Adds temporary location block for verification
- Contacts Let's Encrypt ACME API
- Let's Encrypt sends HTTP-01 challenge
- Certbot responds to challenge
- Let's Encrypt verifies domain ownership
- Downloads signed certificate
- Modifies Nginx config (adds SSL directives)
- Reloads Nginx
- Sets up systemd timer for auto-renewal
Get certificate - Manual (certonly):
# Get certificate without modifying server config
sudo certbot certonly --nginx -d jenkins.ibtisam-iq.com
Get certificate - Standalone (no web server):
# Certbot starts temporary web server on port 80
sudo certbot certonly --standalone -d jenkins.ibtisam-iq.com
Files created:
/etc/letsencrypt/live/jenkins.ibtisam-iq.com/
├── privkey.pem # Private key (keep secret!)
├── fullchain.pem # Certificate + intermediates (use in Nginx)
├── cert.pem # Certificate only
└── chain.pem # Intermediate certificates only
Auto-renewal:
# Check renewal timer
sudo systemctl status certbot.timer
# Test renewal (dry run)
sudo certbot renew --dry-run
# Manual renewal
sudo certbot renew
# Force renewal (even if not expiring)
sudo certbot renew --force-renewal
Advantages:
- Completely automated
- Free forever
- Auto-renewal built-in
- Widely tested and trusted
- Integrates with popular web servers
Disadvantages:
- Requires public IP address
- Requires port 80 or 443 accessible
- Command-line only (no GUI)
- 90-day validity (though auto-renewal handles this)
Method 2: ZeroSSL (Web Dashboard) - Semi-Automated¶
What: Browser-based certificate management Automation Level: Medium (manual via dashboard, API available) Best For: Non-technical users, Windows servers, manual certificate management
Process:
Step 1: Sign up
- Go to zerossl.com
- Create free account
- No credit card required for free tier
Step 2: Create certificate
- Click "New Certificate"
- Enter domain: jenkins.ibtisam-iq.com
- Select 90-day validity (free)
- Click "Next Step"
Step 3: Verify domain ownership
Choose verification method:
Option A: HTTP File Upload
- Download verification file
- Upload to your server:
/.well-known/pki-validation/fileauth.txt - Make accessible via HTTP
- Click "Verify Domain"
Option B: DNS Record
- Get TXT record from ZeroSSL
- Add to your DNS:
Type: TXT Name: _acme-challenge.jenkins.ibtisam-iq.com Value: [provided by ZeroSSL] - Wait for DNS propagation
- Click "Verify Domain"
Option C: Email Verification
- Receive email at admin@ibtisam-iq.com
- Click verification link
- Confirm domain ownership
Step 4: Download certificates
After verification, download: - certificate.crt (your certificate) - ca_bundle.crt (intermediate certificates) - private.key (private key - if generated by ZeroSSL)
Step 5: Combine files
# Create full chain
cat certificate.crt ca_bundle.crt > fullchain.crt
Step 6: Install on server
# Copy files
sudo cp private.key /etc/ssl/private/jenkins.key
sudo cp fullchain.crt /etc/ssl/certs/jenkins-fullchain.crt
# Set permissions
sudo chmod 600 /etc/ssl/private/jenkins.key
sudo chmod 644 /etc/ssl/certs/jenkins-fullchain.crt
# Configure Nginx
sudo nano /etc/nginx/sites-available/jenkins.conf
Advantages:
- User-friendly web interface
- No command line required
- Multiple verification methods
- Can manage from any device
- REST API available for automation
Disadvantages:
- Free tier requires manual renewal every 90 days
- Limited to 3 active certificates on free tier
- Must log in to dashboard regularly
- No automated integration with web servers
Method 3: OpenSSL Self-Signed - Fully Manual¶
What: Generate your own self-signed certificate Automation Level: Full control, manual Best For: Development, testing, internal networks
One-command generation:
openssl req -x509 -newkey rsa:4096 \
-keyout jenkins.key \
-out jenkins.crt \
-days 365 \
-nodes \
-subj "/CN=jenkins.ibtisam-iq.com/O=MyOrg/C=PK"
Flag explanation:
-x509= Output self-signed certificate (not CSR)-newkey rsa:4096= Generate new 4096-bit RSA private key-keyout jenkins.key= Save private key to this file-out jenkins.crt= Save certificate to this file-days 365= Valid for 365 days-nodes= Don't encrypt private key (no password protection)-subj= Certificate subject info (avoids interactive prompts)
Step-by-step generation:
# Step 1: Generate private key
openssl genrsa -out jenkins.key 4096
# Step 2: Create self-signed certificate
openssl req -x509 -new -key jenkins.key -out jenkins.crt -days 365
# You'll be prompted:
# Country Name (2 letter code): PK
# State or Province: Punjab
# Locality (city): Islamabad
# Organization: My Company
# Organizational Unit: IT
# Common Name: jenkins.ibtisam-iq.com <- MUST match domain!
# Email: ...@ibtisam-iq.com
Files created:
jenkins.key # Private key (4096-bit RSA)
jenkins.crt # Self-signed certificate
View certificate:
openssl x509 -in jenkins.crt -text -noout
Advantages:
- Instant creation (no external dependencies)
- Free
- Full control over all parameters
- No rate limits
- Any validity period
- Works offline
Disadvantages:
- Browser warnings ("Not Secure")
- Not trusted by clients
- Manual distribution required for internal use
- No third-party verification
- Not suitable for production public sites
Suppressing browser warnings (NOT recommended for production):
Users must manually trust your certificate:
Chrome:
- Click "Advanced"
- Click "Proceed to jenkins.ibtisam-iq.com (unsafe)"
Firefox:
- Click "Advanced"
- Click "Accept the Risk and Continue"
For testing/internal use - add to trust store:
# Linux
sudo cp jenkins.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
# macOS
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain jenkins.crt
# Windows
# Import via certmgr.msc → Trusted Root Certification Authorities
Method 4: OpenSSL with Private CA - Advanced Manual¶
What: Create your own Certificate Authority, then sign certificates Use Case: Internal networks, Kubernetes, microservices, learning
This is the same process you use in Kubernetes for user certificates!
Step 1: Create your Certificate Authority
# Generate CA private key
openssl genrsa -out ca.key 4096
# Create CA certificate (self-signed root)
openssl req -x509 -new -nodes \
-key ca.key \
-sha256 \
-days 3650 \
-out ca.crt \
-subj "/CN=My Company Root CA/O=MyCompany/C=PK"
Files created:
ca.key # CA private key (keep extremely secure!)
ca.crt # CA root certificate (distribute to all clients)
Step 2: Generate server private key
openssl genrsa -out jenkins.key 4096
Step 3: Create Certificate Signing Request (CSR)
openssl req -new \
-key jenkins.key \
-out jenkins.csr \
-subj "/CN=jenkins.ibtisam-iq.com/O=MyCompany/C=PK"
Step 4: Sign the CSR with your CA
openssl x509 -req \
-in jenkins.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out jenkins.crt \
-days 365 \
-sha256
Files created:
ca.key # CA private key (keep offline/secure)
ca.crt # CA certificate (distribute to clients)
ca.srl # Serial number tracker
jenkins.key # Server private key
jenkins.csr # Certificate signing request
jenkins.crt # Server certificate (signed by your CA)
Step 5: Deploy
Server side:
ssl_certificate /etc/ssl/certs/jenkins.crt;
ssl_certificate_key /etc/ssl/private/jenkins.key;
Client side - add CA to trust store:
# Linux
sudo cp ca.crt /usr/local/share/ca-certificates/mycompany-ca.crt
sudo update-ca-certificates
# Now all certificates signed by your CA are trusted
Advantages:
- Full control over entire PKI
- Can issue unlimited certificates
- Any validity period
- Custom certificate policies
- Ideal for internal infrastructure
- Same workflow as Kubernetes certificates
Disadvantages:
- Must manage CA infrastructure
- Must securely store CA private key
- Must distribute CA certificate to all clients
- Not trusted externally
- More complex than other methods
Real-world example - Kubernetes:
# This is exactly how Kubernetes user certificates work:
# 1. Generate user key
openssl genrsa -out user.key 2048
# 2. Create CSR for user
openssl req -new -key user.key -out user.csr -subj "/CN=user/O=developers"
# 3. Sign with Kubernetes CA
openssl x509 -req -in user.csr -CA /etc/kubernetes/pki/ca.crt \
-CAkey /etc/kubernetes/pki/ca.key -CAcreateserial \
-out user.crt -days 365
# Same process, different context!
Method 5: Cloudflare Tunnel - Zero Certificate Management¶
What: Cloudflare handles all SSL/TLS Automation Level: Completely automatic Best For: No public IP, ephemeral environments, simplest possible setup
How it works:
Browser → Cloudflare (HTTPS terminated here) → Tunnel → Your Server (HTTP)
You never touch certificates!
Setup:
# Install cloudflared
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o cloudflared
chmod +x cloudflared
sudo mv cloudflared /usr/local/bin/
# Install as service (token from Cloudflare dashboard)
sudo cloudflared service install eyJhIjoiXXXXXXXXXX...
# Configure in dashboard
# Subdomain: jenkins
# Domain: ibtisam-iq.com
# Service: http://localhost:8080
Result:
https://jenkins.ibtisam-iq.comworks immediately- Cloudflare's certificate is used
- No certificate files on your server
- No renewal needed
- Works without public IP
Behind the scenes:
- Cloudflare has wildcard certificate for
*.cfargotunnel.com - Your domain CNAMEs to Cloudflare
- Cloudflare terminates SSL/TLS
- Sends plain HTTP through tunnel to your server
- Server doesn't need HTTPS at all
Advantages:
- Zero certificate management
- No public IP required
- Free
- Automatic HTTPS
- Works behind NAT/firewall
- DDoS protection included
- Automatic certificate renewal (handled by Cloudflare)
Disadvantages:
- Dependent on Cloudflare service
- TLS termination at Cloudflare (not end-to-end)
- Must use Cloudflare DNS
- Adds latency (one extra hop)
- Less control over TLS configuration
When to use:
- iximiuz Labs or similar platforms
- Development environments
- Temporary demos
- No public IP available
- Want simplest possible setup
Method 6: AWS Certificate Manager (ACM) - AWS Cloud Only¶
What: AWS managed certificate service Automation Level: Fully automated Best For: AWS infrastructure (ALB, CloudFront, API Gateway)
Process:
Step 1: Request certificate
# Via AWS Console
1. Go to Certificate Manager
2. Click "Request a certificate"
3. Enter domain: jenkins.ibtisam-iq.com
4. Choose validation: DNS or Email
# Via AWS CLI
aws acm request-certificate \
--domain-name jenkins.ibtisam-iq.com \
--validation-method DNS
Step 2: Validate domain
DNS Validation (recommended):
# ACM provides CNAME record
# Add to Route 53 or your DNS:
Name: _abc123.jenkins.ibtisam-iq.com
Value: _xyz789.acm-validations.aws.
Email Validation:
# ACM sends email to:
# admin@ibtisam-iq.com
# administrator@ibtisam-iq.com
# hostmaster@ibtisam-iq.com
# postmaster@ibtisam-iq.com
# webmaster@ibtisam-iq.com
Step 3: Attach to AWS resource
# Cannot export certificate!
# Can only attach to AWS services:
# - Application Load Balancer (ALB)
# - CloudFront distribution
# - API Gateway
# - Elastic Beanstalk
Example - ALB:
aws elbv2 create-listener \
--load-balancer-arn arn:aws:elasticloadbalancing:... \
--protocol HTTPS \
--port 443 \
--certificates CertificateArn=arn:aws:acm:... \
--default-actions Type=forward,TargetGroupArn=arn:aws:...
Advantages:
- Free (when used with AWS services)
- Automatic renewal
- AWS manages everything
- Integrates with AWS services
- No certificate files to manage
- Wildcard certificates supported
Disadvantages:
- AWS services only (cannot export)
- Cannot use on EC2 directly
- Vendor lock-in
- Must use AWS DNS validation or email
- No access to private key
When to use:
- Using AWS ALB, CloudFront, or API Gateway
- Want zero certificate management
- Already in AWS ecosystem
- Cost-conscious (free for AWS services)
Manual Certificate Generation (Complete Process)¶
Understanding the Full Certificate Lifecycle¶
The complete workflow:
1. Generate Private Key
↓
2. Create Certificate Signing Request (CSR)
↓
3. Submit CSR to Certificate Authority
↓
4. CA Validates Domain Ownership
↓
5. CA Signs Certificate
↓
6. Download Signed Certificate
↓
7. Combine with Intermediate Certificates
↓
8. Install on Server
↓
9. Configure Web Server
↓
10. Test and Verify
Let's go through each step in detail.
Step 1: Generate Private Key¶
What: Create cryptographic key pair
# Generate 4096-bit RSA private key
openssl genrsa -out jenkins.key 4096
# Alternative: Generate with password protection
openssl genrsa -aes256 -out jenkins.key 4096
# You'll be prompted for passphrase
Key size recommendations:
- 2048 bits: Minimum acceptable, fast
- 3072 bits: Good security/performance balance
- 4096 bits: Maximum security, slower (recommended)
Output:
Generating RSA private key, 4096 bit long modulus
....++
.......................++
e is 65537 (0x10001)
File created: jenkins.key
View key information:
openssl rsa -in jenkins.key -text -noout
Check key:
# Verify key is valid RSA
openssl rsa -in jenkins.key -check
# Get key's public modulus (for matching with certificate)
openssl rsa -in jenkins.key -modulus -noout | openssl md5
Security:
# Set restrictive permissions
chmod 600 jenkins.key
# Never commit to git
echo "*.key" >> .gitignore
# Store backup in secure location
# Consider encrypting backup
openssl rsa -aes256 -in jenkins.key -out jenkins.key.encrypted
Step 2: Create Certificate Signing Request (CSR)¶
What: Request file containing your information and public key
# Interactive mode
openssl req -new -key jenkins.key -out jenkins.csr
# Non-interactive mode (with all info in command)
openssl req -new -key jenkins.key -out jenkins.csr \
-subj "/C=PK/ST=Punjab/L=Rawalpindi/O=My Company/OU=IT/CN=jenkins.ibtisam-iq.com/emailAddress=admin@ibtisam-iq.com"
Interactive prompts:
Country Name (2 letter code) []: PK
State or Province Name (full name) []: Punjab
Locality Name (city, town) []: Rawalpindi
Organization Name (company) []: My Company
Organizational Unit Name (department) []: IT Department
Common Name (FQDN) []: jenkins.ibtisam-iq.com
Email Address []: admin@ibtisam-iq.com
A challenge password []: [Leave empty]
An optional company name []: [Leave empty]
Critical: Common Name (CN)
- MUST exactly match your domain
- Single domain:
jenkins.ibtisam-iq.com - Wildcard:
*.ibtisam-iq.com(matches jenkins.ibtisam-iq.com, api.ibtisam-iq.com, etc.) - Multiple domains: Use Subject Alternative Name (SAN) extension
SAN (Subject Alternative Names) - Multiple domains:
# Create OpenSSL config file
cat > san.cnf <<EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
countryName = PK
stateOrProvinceName = Punjab
localityName = Rawalpindi
organizationName = My Company
commonName = jenkins.ibtisam-iq.com
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = jenkins.ibtisam-iq.com
DNS.2 = www.jenkins.ibtisam-iq.com
DNS.3 = api.ibtisam-iq.com
EOF
# Generate CSR with SAN
openssl req -new -key jenkins.key -out jenkins.csr -config san.cnf
File created: jenkins.csr
View CSR:
openssl req -in jenkins.csr -text -noout
Verify CSR:
# Check CSR is valid
openssl req -in jenkins.csr -noout -verify
# Extract public key from CSR
openssl req -in jenkins.csr -pubkey -noout
# Get CSR modulus (to verify it matches private key)
openssl req -in jenkins.csr -modulus -noout | openssl md5
Step 3: Submit CSR to Certificate Authority¶
Let's Encrypt (automated):
# Certbot handles CSR creation internally
sudo certbot certonly --nginx -d jenkins.ibtisam-iq.com
ZeroSSL (manual):
- Log in to zerossl.com
- Click "New Certificate"
- Click "Certificate Signing Request (CSR)"
- Paste contents of jenkins.csr
- Click "Next"
Commercial CA (varies):
- Go to CA's website
- Choose certificate type (DV/OV/EV)
- Fill order form
- Paste CSR when prompted
- Complete payment
- Proceed to validation
View CSR content:
cat jenkins.csr
Output will be:
-----BEGIN CERTIFICATE REQUEST-----
MIIEojCCAooCAQAwYTELMAkGA1UEBhMCUEsxDzANBgNVBAgMBlB1bmphYjEU...
(base64 encoded data)
...
-----END CERTIFICATE REQUEST-----
Step 4: Domain Validation¶
CA must verify you own the domain. Methods:
HTTP-01 Challenge (Most Common)¶
How it works:
1. CA gives you a token: abc123xyz
2. You create file: /.well-known/acme-challenge/abc123xyz
3. File contains: abc123xyz.YOUR_ACCOUNT_KEY
4. CA fetches: http://jenkins.ibtisam-iq.com/.well-known/acme-challenge/abc123xyz
5. CA verifies content matches
6. Domain ownership proven!
Manual setup:
# Create directory
sudo mkdir -p /var/www/html/.well-known/acme-challenge/
# Create verification file (content provided by CA)
echo "abc123xyz.ACCOUNT_KEY" | sudo tee /var/www/html/.well-known/acme-challenge/abc123xyz
# Verify accessible
curl http://jenkins.ibtisam-iq.com/.well-known/acme-challenge/abc123xyz
Nginx configuration:
server {
listen 80;
server_name jenkins.ibtisam-iq.com;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
}
Certbot does this automatically!
DNS-01 Challenge¶
How it works:
1. CA gives you TXT record value: abc123xyz
2. You add DNS TXT record:
Name: _acme-challenge.jenkins.ibtisam-iq.com
Value: abc123xyz
3. Wait for DNS propagation
4. CA queries DNS for TXT record
5. CA verifies value matches
6. Domain ownership proven!
Add DNS record (Cloudflare example):
# In Cloudflare dashboard:
Type: TXT
Name: _acme-challenge.jenkins
Content: [value from CA]
TTL: Auto
Verify DNS propagation:
dig TXT _acme-challenge.jenkins.ibtisam-iq.com
# or
nslookup -type=TXT _acme-challenge.jenkins.ibtisam-iq.com
Advantage of DNS-01:
- Works without web server running
- Can get wildcard certificates
- Works behind firewall
Email Validation¶
How it works:
1. CA sends email to admin addresses:
- admin@ibtisam-iq.com
- administrator@ibtisam-iq.com
- hostmaster@ibtisam-iq.com
- postmaster@ibtisam-iq.com
- webmaster@ibtisam-iq.com
2. You receive email with verification link
3. Click link to confirm
4. Domain ownership proven!
Less common for automated systems.
Step 5: Receive Signed Certificate¶
After validation, CA signs your certificate and returns:
Files you'll receive:
- Your Certificate:
jenkins.crtorcertificate.crt - Intermediate Certificate(s):
intermediate.crtorca_bundle.crt - Root Certificate: Usually not needed (already in browsers)
Download from CA:
Let's Encrypt (via Certbot):
# Automatically saved to:
/etc/letsencrypt/live/jenkins.ibtisam-iq.com/
├── cert.pem # Your certificate
├── chain.pem # Intermediate certs
├── fullchain.pem # cert.pem + chain.pem
└── privkey.pem # Your private key
ZeroSSL (from dashboard):
# Download ZIP containing:
# - certificate.crt
# - ca_bundle.crt
# Extract and rename
unzip certificate.zip
mv certificate.crt jenkins.crt
mv ca_bundle.crt intermediate.crt
Commercial CA (via email or dashboard):
- Download from order details page
- Or receive via email
- May be in various formats (.crt, .pem, .cer)
Step 6: Verify Certificate¶
View certificate details:
openssl x509 -in jenkins.crt -text -noout
Output shows:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 03:1a:2b:3c:...
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, O=Let's Encrypt, CN=R3
Validity
Not Before: Feb 17 02:00:00 2026 GMT
Not After : May 18 02:00:00 2026 GMT
Subject: CN=jenkins.ibtisam-iq.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
Verify certificate matches private key:
# Get private key modulus
openssl rsa -in jenkins.key -modulus -noout | openssl md5
# Get certificate modulus
openssl x509 -in jenkins.crt -modulus -noout | openssl md5
# Both should output same MD5 hash!
# If they match, certificate and key are a pair
Check certificate expiry:
openssl x509 -in jenkins.crt -noout -dates
# Output:
# notBefore=Feb 17 02:00:00 2026 GMT
# notAfter=May 18 02:00:00 2026 GMT
Verify certificate chain:
# Verify against CA bundle
openssl verify -CAfile intermediate.crt jenkins.crt
# Should output: jenkins.crt: OK
Step 7: Create Full Chain¶
Why: Browsers need complete chain to verify trust path
# Combine certificate + intermediate(s)
cat jenkins.crt intermediate.crt > fullchain.crt
# Or if you have multiple intermediates
cat jenkins.crt intermediate1.crt intermediate2.crt > fullchain.crt
Verify full chain:
# Check how many certificates in file
openssl crl2pkcs7 -nocrl -certfile fullchain.crt | openssl pkcs7 -print_certs -noout
# View each certificate
openssl storeutl -noout -text -certs fullchain.crt
Step 8: Install on Server¶
Organize files:
# Copy to standard locations
sudo cp jenkins.key /etc/ssl/private/
sudo cp fullchain.crt /etc/ssl/certs/jenkins-fullchain.crt
# Set permissions
sudo chmod 600 /etc/ssl/private/jenkins.key
sudo chmod 644 /etc/ssl/certs/jenkins-fullchain.crt
# Set ownership
sudo chown root:root /etc/ssl/private/jenkins.key
sudo chown root:root /etc/ssl/certs/jenkins-fullchain.crt
Step 9: Configure Web Server¶
Nginx:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name jenkins.ibtisam-iq.com;
# Certificate files
ssl_certificate /etc/ssl/certs/jenkins-fullchain.crt;
ssl_certificate_key /etc/ssl/private/jenkins.key;
# 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';
ssl_prefer_server_ciphers off;
# SSL session caching
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/certs/jenkins-fullchain.crt;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Redirect HTTP to HTTPS
server {
listen 80;
listen [::]:80;
server_name jenkins.ibtisam-iq.com;
return 301 https://$server_name$request_uri;
}
Test configuration:
sudo nginx -t
Reload Nginx:
sudo systemctl reload nginx
Step 10: Test and Verify¶
Check HTTPS works:
curl -I https://jenkins.ibtisam-iq.com
Test SSL configuration:
# Check certificate from command line
echo | openssl s_client -connect jenkins.ibtisam-iq.com:443 -servername jenkins.ibtisam-iq.com 2>/dev/null | openssl x509 -noout -dates
# Test SSL handshake
openssl s_client -connect jenkins.ibtisam-iq.com:443 -servername jenkins.ibtisam-iq.com
Online SSL testing tools:
- SSL Labs: https://www.ssllabs.com/ssltest/
- Check for A+ rating
Browser testing:
- Open https://jenkins.ibtisam-iq.com
- Check for green padlock
- Click padlock → View certificate
- Verify:
- Domain matches
- Valid date range
- Trusted chain
Common issues:
ERR_CERT_COMMON_NAME_INVALID:
- Certificate CN doesn't match domain
- Solution: Generate new certificate with correct CN
ERR_CERT_AUTHORITY_INVALID:
- Certificate not signed by trusted CA (self-signed)
- Or missing intermediate certificates
- Solution: Include fullchain.pem in Nginx config
ERR_CERT_DATE_INVALID:
- Certificate expired or not yet valid
- Solution: Renew certificate
Let's Encrypt vs ZeroSSL vs Commercial CAs¶
Feature Comparison Matrix¶
| Feature | Let's Encrypt | ZeroSSL Free | ZeroSSL Paid | Commercial CAs |
|---|---|---|---|---|
| Cost | Free | Free | $4-8/mo | \(50-\)1500/yr |
| Validity | 90 days | 90 days | 90-365 days | 365 days |
| Auto-renewal | Yes (Certbot) | No | Yes | Varies |
| DV Certificates | Yes | Yes | Yes | Yes |
| OV Certificates | No | No | Yes | Yes |
| EV Certificates | No | No | No | Yes |
| Wildcard | Free | Free | Free | $200-500/yr |
| SAN (Multi-domain) | Free | Free | Free | Extra cost |
| Rate Limits | 50/week | 3 active | Unlimited | Unlimited |
| API | ACME | REST | REST | Varies |
| Interface | CLI only | Web + CLI | Web + CLI | Web + CLI |
| Support | Community | Community | 24/7 Phone | |
| Warranty | None | None | None | Up to $1.75M |
| Compliance certs | No | No | No | Yes (SOC2, etc) |
| Best for | Automation | Manual setup | Small business | Enterprise |
Detailed Comparison¶
Let's Encrypt¶
Pros:
- ✅ Completely free forever
- ✅ Fully automated (Certbot, ACME)
- ✅ Trusted by all major browsers
- ✅ Wildcard certificates included
- ✅ Unlimited SANs per certificate
- ✅ Open source and transparent
- ✅ Backed by major tech companies
- ✅ Strong community support
- ✅ Well-documented
Cons:
- ❌ 90-day validity (security feature, but requires attention)
- ❌ No OV/EV certificates
- ❌ No commercial support
- ❌ Command-line only (no GUI)
- ❌ Rate limits can be hit in testing
- ❌ Requires automation for best experience
Rate Limits:
- 50 certificates per registered domain per week
- 5 duplicate certificates per week
- 300 new orders per account per 3 hours
- Rarely an issue for production use
Best use cases:
- Personal websites and blogs
- Startups and small to medium businesses
- Automated CI/CD pipelines
- Microservices and APIs
- Any scenario where automation is possible
- Developers comfortable with command line
Not suitable for:
- Organizations requiring OV/EV validation
- Environments without automation capability
- Enterprises needing SLA guarantees
- Situations requiring commercial support
ZeroSSL¶
Pros:
- ✅ Free tier available
- ✅ Web dashboard (easier for beginners)
- ✅ Multiple verification methods
- ✅ REST API for automation
- ✅ Can generate from browser
- ✅ Paid plans add features
- ✅ Commercial support available
- ✅ Compatible with ACME protocol
Cons:
- ❌ Free tier limited to 3 active certificates
- ❌ Free certificates need manual renewal
- ❌ Dashboard can be slow
- ❌ Less mature than Let's Encrypt
- ❌ API rate limits on free tier
- ❌ Some features behind paywall
Free vs Paid:
Free:
- 3 active certificates
- 90-day validity
- Manual renewal
- Community support
- Basic dashboard
Paid (from $3.99/month):
- Unlimited certificates
- Auto-renewal
- Email support
- Priority validation
- API access
- Certificate management tools
Best use cases:
- Non-technical users preferring GUI
- Small teams managing certificates manually
- Windows servers
- Projects that might need OV later
- Need for web-based management
Not suitable for:
- Large-scale automated deployments (use Let's Encrypt)
- When free tier limits are exceeded
- Enterprise environments (use commercial CA)
Commercial CAs (DigiCert, Sectigo, etc.)¶
Pros:
- ✅ Organization Validation (OV)
- ✅ Extended Validation (EV)
- ✅ 24/7 phone and email support
- ✅ Warranty/insurance coverage
- ✅ Compliance certifications
- ✅ Account manager for enterprise
- ✅ Integration assistance
- ✅ Better for audits and compliance
Cons:
- ❌ Expensive (\(50-\)1500+/year)
- ❌ Overkill for most use cases
- ❌ Manual processes often involved
- ❌ Longer issuance time for OV/EV
- ❌ Annual renewal required
Price ranges:
- DV: $50-150/year
- OV: $100-300/year
- EV: $200-1500/year
- Wildcard DV: $150-400/year
- Wildcard OV: $300-800/year
- Multi-domain (SAN): Add $50-100 per additional domain
Warranty coverage:
- DV: Up to $10,000
- OV: Up to $250,000
- EV: Up to $1,750,000
Best use cases:
- Banks and financial institutions
- E-commerce with high transaction volume
- Healthcare (HIPAA compliance)
- Government websites
- Enterprise corporate sites
- When compliance requires OV/EV
- Organizations with ample budget
- Need for SLA and guaranteed uptime
Not suitable for:
- Personal websites (use Let's Encrypt)
- Startups watching costs (use Let's Encrypt)
- Simple blogs and portfolios (use Let's Encrypt)
- Projects prioritizing automation (use Let's Encrypt)
Decision Matrix¶
Use Let's Encrypt if:
- ✅ Budget is zero
- ✅ Have automation capability
- ✅ Server has public IP and open ports
- ✅ DV certificate is sufficient
- ✅ Comfortable with command line
- ✅ Want maximum automation
- ✅ Open to 90-day renewal cycle
Use ZeroSSL if:
- ✅ Prefer web interface
- ✅ Managing < 3 certificates manually
- ✅ Might need paid features later
- ✅ Windows server environment
- ✅ Want REST API option
- ✅ Need email support (paid tier)
Use Commercial CA if:
- ✅ Need OV or EV validation
- ✅ Budget allows ($100+/year)
- ✅ Compliance requirements demand it
- ✅ Want warranty/insurance
- ✅ Need 24/7 support
- ✅ Enterprise environment
- ✅ Audit requirements
Use Cloudflare Tunnel if:
- ✅ No public IP available
- ✅ Don't want ANY certificate management
- ✅ Ephemeral environments
- ✅ Want simplest possible solution
- ✅ Already using Cloudflare
Cost Over 5 Years¶
| Solution | Initial | Annual | 5 Years | Notes |
|---|---|---|---|---|
| Let's Encrypt | $0 | $0 | $0 | Time cost: setup automation once |
| ZeroSSL Free | $0 | $0 | $0 | Time cost: manual renewal every 90 days |
| ZeroSSL Paid | $0 | $48 | $240 | Basic paid plan |
| Commercial DV | $75 | $75 | $375 | Entry-level commercial |
| Commercial OV | $200 | $200 | $1,000 | Business-grade |
| Commercial EV | $300 | $300 | $1,500 | Premium validation |
Time investment comparison:
Let's Encrypt:
- Initial setup: 30-60 minutes
- Ongoing: 0 minutes (automatic)
- Total over 5 years: 1 hour
ZeroSSL Free:
- Initial setup: 15-30 minutes
- Manual renewal: 15 minutes every 90 days
- Total over 5 years: 15 hours (60 renewals × 15 min)
Commercial CA:
- Initial setup: 30-60 minutes
- Annual renewal: 30 minutes
- Total over 5 years: 3.5 hours
Cloudflare Tunnel:
- Initial setup: 10-15 minutes
- Ongoing: 0 minutes
- Total over 5 years: 15 minutes
Technical Differences¶
Validation Methods¶
Let's Encrypt:
- HTTP-01 (web server challenge)
- DNS-01 (DNS TXT record)
- TLS-ALPN-01 (TLS-based challenge)
- Fully automated
ZeroSSL:
- HTTP file upload
- DNS CNAME record
- Email verification
- Manual or API-driven
Commercial CAs:
- Email validation
- DNS validation
- File-based validation
- Phone verification (OV/EV)
- Business registration verification (OV/EV)
- Physical address verification (EV)
Certificate Issuance Time¶
| CA Type | DV | OV | EV |
|---|---|---|---|
| Let's Encrypt | 1-2 minutes | N/A | N/A |
| ZeroSSL | 5-15 minutes | N/A | N/A |
| Commercial | 5-60 minutes | 1-3 days | 1-2 weeks |
Trust Store Presence¶
All three are trusted by:
- ✅ Chrome
- ✅ Firefox
- ✅ Safari
- ✅ Edge
- ✅ Opera
- ✅ Mobile browsers
- ✅ curl, wget, etc.
No difference in browser trust!
Using Certificates in Different Services¶
Nginx¶
Most common web server configuration:
# HTTPS server block
server {
# Listen on HTTPS port
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name jenkins.ibtisam-iq.com;
# Certificate and key locations
ssl_certificate /etc/letsencrypt/live/jenkins.ibtisam-iq.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/jenkins.ibtisam-iq.com/privkey.pem;
# Modern TLS 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;
# SSL session caching for performance
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# OCSP Stapling for faster certificate validation
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/jenkins.ibtisam-iq.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Diffie-Hellman parameter for DHE ciphersuites
ssl_dhparam /etc/ssl/certs/dhparam.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Proxy to backend
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}
# Redirect HTTP to HTTPS
server {
listen 80;
listen [::]:80;
server_name jenkins.ibtisam-iq.com;
return 301 https://$host$request_uri;
}
Generate DH parameters (one-time):
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
# Takes 10-30 minutes, only need to do once
Test configuration:
sudo nginx -t
Reload Nginx:
sudo systemctl reload nginx
Files needed: - fullchain.pem - Your certificate + intermediate chain - privkey.pem - Private key
Apache¶
<VirtualHost *:443>
ServerName jenkins.ibtisam-iq.com
ServerAdmin admin@ibtisam-iq.com
# Enable SSL
SSLEngine on
# Certificate files
SSLCertificateFile /etc/ssl/certs/jenkins.crt
SSLCertificateKeyFile /etc/ssl/private/jenkins.key
SSLCertificateChainFile /etc/ssl/certs/intermediate.crt
# Modern TLS configuration
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
SSLCompression off
SSLSessionTickets off
# OCSP Stapling
SSLUseStapling on
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
# Security headers
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
# Proxy to backend
ProxyPreserveHost On
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
</VirtualHost>
# Redirect HTTP to HTTPS
<VirtualHost *:80>
ServerName jenkins.ibtisam-iq.com
Redirect permanent / https://jenkins.ibtisam-iq.com/
</VirtualHost>
Enable required Apache modules:
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod headers
sudo systemctl restart apache2
Files needed:
jenkins.crt- Your certificate onlyjenkins.key- Private keyintermediate.crt- Intermediate certificates
Jenkins Direct (No Reverse Proxy)¶
Jenkins can handle HTTPS directly, but requires PKCS#12 format.
Step 1: Convert certificate to PKCS#12:
openssl pkcs12 -export \
-in /etc/letsencrypt/live/jenkins.ibtisam-iq.com/fullchain.pem \
-inkey /etc/letsencrypt/live/jenkins.ibtisam-iq.com/privkey.pem \
-out /var/lib/jenkins/jenkins.p12 \
-name jenkins \
-passout pass:changeit
# Set ownership
sudo chown jenkins:jenkins /var/lib/jenkins/jenkins.p12
sudo chmod 600 /var/lib/jenkins/jenkins.p12
Step 2: Configure Jenkins:
sudo nano /etc/default/jenkins
Add these flags to JENKINS_ARGS:
JENKINS_ARGS="--httpsPort=8443 \
--httpPort=-1 \
--httpsKeyStore=/var/lib/jenkins/jenkins.p12 \
--httpsKeyStorePassword=changeit"
Step 3: Restart Jenkins:
sudo systemctl restart jenkins
Access Jenkins:
https://jenkins.ibtisam-iq.com:8443
Note: Reverse proxy (Nginx/Apache) is still recommended for:
- Standard HTTPS port (443 vs 8443)
- Better SSL/TLS configuration options
- Easier certificate renewal
- Additional security features
Files needed: - jenkins.p12 - PKCS#12 bundle (certificate + private key)
Tomcat¶
Step 1: Convert to PKCS#12:
openssl pkcs12 -export \
-in cert.pem \
-inkey privkey.pem \
-out tomcat.p12 \
-name tomcat \
-CAfile chain.pem \
-caname root \
-password pass:changeit
Step 2: Configure Tomcat:
<!-- Edit: /etc/tomcat9/server.xml -->
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<SSLHostConfig>
<Certificate certificateKeystoreFile="/etc/tomcat9/tomcat.p12"
certificateKeystorePassword="changeit"
certificateKeystoreType="PKCS12"
type="RSA" />
</SSLHostConfig>
</Connector>
Step 3: Restart Tomcat:
sudo systemctl restart tomcat9
Docker¶
docker-compose.yml:
version: '3.8'
services:
nginx:
image: nginx:latest
ports:
- "443:443"
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- /etc/letsencrypt/live/jenkins.ibtisam-iq.com/fullchain.pem:/etc/nginx/ssl/cert.pem:ro
- /etc/letsencrypt/live/jenkins.ibtisam-iq.com/privkey.pem:/etc/nginx/ssl/key.pem:ro
depends_on:
- jenkins
jenkins:
image: jenkins/jenkins:lts
ports:
- "8080:8080"
volumes:
- jenkins_home:/var/jenkins_home
volumes:
jenkins_home:
nginx.conf:
events {
worker_connections 1024;
}
http {
upstream jenkins {
server jenkins:8080;
}
server {
listen 443 ssl;
server_name jenkins.ibtisam-iq.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://jenkins;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name jenkins.ibtisam-iq.com;
return 301 https://$host$request_uri;
}
}
Kubernetes¶
Create TLS secret:
kubectl create secret tls jenkins-tls \
--cert=/etc/letsencrypt/live/jenkins.ibtisam-iq.com/fullchain.pem \
--key=/etc/letsencrypt/live/jenkins.ibtisam-iq.com/privkey.pem \
--namespace=default
Or from files:
kubectl create secret tls jenkins-tls \
--cert=fullchain.pem \
--key=privkey.pem
Verify secret:
kubectl describe secret jenkins-tls
Ingress with TLS:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jenkins-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
cert-manager.io/cluster-issuer: "letsencrypt-prod" # If using cert-manager
spec:
tls:
- hosts:
- jenkins.ibtisam-iq.com
secretName: jenkins-tls
rules:
- host: jenkins.ibtisam-iq.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jenkins
port:
number: 8080
Using cert-manager for automatic certificates:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: ...@ibtisam-iq.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
This is exactly like creating user certificates in Kubernetes - same concept, different purpose!
Understanding the Certificate Chain¶
What is Certificate Chain?¶
Definition: Series of certificates linking your certificate to a trusted root CA.
Analogy: Chain of trust, like verifying someone's identity through mutual friends:
You meet a stranger (website) →
Stranger shows ID signed by your friend (intermediate CA) →
You trust your friend →
Your friend's ID was signed by government (root CA) →
You trust government →
Therefore, you trust stranger!
Why Certificate Chains Exist¶
Problem: Root CA private keys are incredibly valuable
If root CA compromised:
- All certificates worldwide become untrustworthy
- Browsers must remove CA from trust store
- Millions of websites affected
- Years to recover
Solution: Intermediate certificates act as buffer
Root CA (kept offline, extremely secure)
↓ signs
Intermediate CA (used daily for signing)
↓ signs
Your Certificate
If intermediate compromised:
- Only certificates from that intermediate affected
- Root CA can revoke compromised intermediate
- Issue new intermediate
- Root CA stays safe
- Recovery measured in days, not years
The Chain Structure¶
Typical Let's Encrypt chain:
ISRG Root X1 (Root CA)
↓ signed by
Let's Encrypt Authority X3 (Intermediate CA)
↓ signed by
jenkins.ibtisam-iq.com (Your Certificate)
Typical ZeroSSL chain:
USERTrust RSA Certification Authority (Root CA)
↓ signed by
Sectigo RSA Domain Validation Secure Server CA (Intermediate CA)
↓ signed by
jenkins.ibtisam-iq.com (Your Certificate)
Commercial CA chain (may have multiple intermediates):
DigiCert Global Root CA (Root CA)
↓ signed by
DigiCert SHA2 Secure Server CA (Intermediate CA 1)
↓ signed by
DigiCert TLS RSA SHA256 2020 CA1 (Intermediate CA 2)
↓ signed by
jenkins.ibtisam-iq.com (Your Certificate)
How Browsers Verify Chains¶
Step-by-step verification:
1. Browser receives your certificate
2. Certificate says "I'm jenkins.ibtisam-iq.com, signed by Let's Encrypt Authority X3"
3. Browser checks: "Do I have Let's Encrypt Authority X3?"
- If in trust store → ✅ Trust
- If not → Check intermediate certificate
4. Intermediate certificate says "I'm Let's Encrypt Authority X3, signed by ISRG Root X1"
5. Browser checks: "Do I have ISRG Root X1?"
- If in trust store → ✅ Trust entire chain
- If not → ⚠️ Not trusted
6. All checks pass → 🔒 Green padlock
Browser trust store:
- Pre-installed list of root CAs
- Usually 100-150 root certificates
- Updated with browser/OS updates
- Can manually add/remove roots
Missing Chain Problem¶
Common issue: Incomplete certificate chain
Symptoms:
- Works in Chrome
- Fails in Firefox
- Fails in curl
- Error: "Unable to verify certificate chain"
Why Chrome works:
- Chrome caches intermediate certificates
- If Chrome saw intermediate before, it remembers
- Creates false sense of security
Why others fail:
- Firefox doesn't cache intermediates
- curl requires complete chain
- Mobile browsers may not cache
Diagnosis:
# Test with curl
curl https://jenkins.ibtisam-iq.com
# If error:
# curl: (60) SSL certificate problem: unable to get local issuer certificate
# → Missing intermediate certificate
Fix:
# Wrong - only your certificate
ssl_certificate /path/to/cert.pem;
# Correct - certificate + intermediates
ssl_certificate /path/to/fullchain.pem;
Viewing Certificate Chain¶
OpenSSL command:
openssl s_client -connect jenkins.ibtisam-iq.com:443 -showcerts
Output shows full chain:
depth=2 C=US, O=Internet Security Research Group, CN=ISRG Root X1
verify return:1
depth=1 C=US, O=Let's Encrypt, CN=R3
verify return:1
depth=0 CN=jenkins.ibtisam-iq.com
verify return:1
---
Certificate chain
0 s:CN=jenkins.ibtisam-iq.com
i:C=US, O=Let's Encrypt, CN=R3
-----BEGIN CERTIFICATE-----
(Your certificate)
-----END CERTIFICATE-----
1 s:C=US, O=Let's Encrypt, CN=R3
i:C=US, O=Internet Security Research Group, CN=ISRG Root X1
-----BEGIN CERTIFICATE-----
(Intermediate certificate)
-----END CERTIFICATE-----
---
Verify chain locally:
# Verify against system trust store
openssl verify -CApath /etc/ssl/certs fullchain.pem
# Should output: fullchain.pem: OK
Certificate Chain Files¶
cert.pem (your certificate only):
-----BEGIN CERTIFICATE-----
(Your certificate for jenkins.ibtisam-iq.com)
-----END CERTIFICATE-----
chain.pem (intermediates only):
-----BEGIN CERTIFICATE-----
(Intermediate certificate 1)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Intermediate certificate 2 - if exists)
-----END CERTIFICATE-----
fullchain.pem (complete chain):
-----BEGIN CERTIFICATE-----
(Your certificate for jenkins.ibtisam-iq.com)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Intermediate certificate 1)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Intermediate certificate 2 - if exists)
-----END CERTIFICATE-----
Creating fullchain manually:
# Concatenate certificate + intermediates
cat cert.pem intermediate.crt > fullchain.pem
# Or with multiple intermediates
cat cert.pem intermediate1.crt intermediate2.crt > fullchain.pem
Root Certificates¶
Why not include root in chain?
Browsers already have root certificates installed!
Including root would:
- Waste bandwidth
- Provide no additional security
- Is unnecessary duplication
Browser trust store location:
Linux:
/etc/ssl/certs/ca-certificates.crt
/etc/ssl/certs/ca-bundle.crt
/usr/share/ca-certificates/
macOS:
/System/Library/Keychains/SystemRootCertificates.keychain
# GUI: Keychain Access → System Roots
Windows:
certmgr.msc → Trusted Root Certification Authorities
View system roots:
# List all trusted CAs
ls /etc/ssl/certs/
# View specific CA certificate
openssl x509 -in /etc/ssl/certs/DigiCert_Global_Root_CA.pem -text -noout
Cross-Signing¶
What: Root CA signed by another root CA
Why: Compatibility with older systems
Example: Let's Encrypt
Old chain (compatibility):
ISRG Root X1 (Let's Encrypt) → Signed by DST Root CA X3 (old, widely trusted)
New chain (after DST expiration):
ISRG Root X1 (Let's Encrypt) → Self-signed
Impact:
- Android < 7.1.1 doesn't trust ISRG Root X1 directly
- Needed DST Root CA X3 signature
- DST Root CA X3 expired September 2021
- Modern devices use new chain
- Old devices may have issues
Chain Validation Errors¶
Common errors and solutions:
ERR_CERT_AUTHORITY_INVALID:
Cause: Chain doesn't lead to trusted root
Solution: Include intermediate certificates in fullchain.pem
SSL_ERROR_BAD_CERT_DOMAIN:
Cause: Certificate domain doesn't match URL
Solution: Generate certificate with correct Common Name
ERR_CERT_COMMON_NAME_INVALID:
Cause: Accessing site with different domain than certificate
Solution: Access site using exact domain in certificate
ERR_CERT_DATE_INVALID:
Cause: Certificate expired or not yet valid
Solution: Renew certificate, check system clock
MOZILLA_PKIX_ERROR_MITM_DETECTED:
Cause: Antivirus/firewall intercepting HTTPS
Solution: Disable SSL inspection, add exception
Key Takeaways¶
Files You Must Know¶
| File | Purpose | Share? | Where Used |
|---|---|---|---|
privkey.pem / .key | Private key | 🔒 NEVER | Server only (decrypt traffic) |
cert.pem / .crt | Your certificate | ✅ Yes | Server + sent to clients |
.csr | Certificate request | ✅ Yes | Submit to CA, then discard |
chain.pem | Intermediate certs | ✅ Yes | Server (trust chain) |
fullchain.pem | Cert + chain | ✅ Yes | Nginx, Apache (complete chain) |
.p12 / .pfx | Bundle (cert+key) | 🔒 Password protect | Jenkins, Tomcat, Windows |
Certificate Types¶
Self-Signed:
- You sign it yourself
- Browser warnings
- Free, instant, full control
- Only for dev/testing
CA-Signed:
- Trusted authority signs it
- No browser warnings
- Industry standard
- For production sites
Certificate Authorities¶
Let's Encrypt:
- Free, automated, 90-day validity
- Best for most use cases
ZeroSSL:
- Free tier with web dashboard
- Good for manual management
Commercial CAs:
- Expensive, OV/EV available
- For enterprises with compliance needs
Cloudflare Tunnel:
- No certificates needed!
- Best for no public IP scenarios
The Complete Process¶
Generate Key → Create CSR → Submit to CA → Domain Validation →
Receive Certificate → Create Full Chain → Install on Server →
Configure Service → Test → Renew Before Expiry
Not About Memorizing Commands¶
Understand:
- What each file contains and does
- Why certificate chains exist
- When to use which method
- How to verify everything works
- How to troubleshoot issues
Like Kubernetes:
- You know what
.crtand.keyfiles are - You can create secrets from them
- You can configure any service that needs them
- Same knowledge, different context
Connection to Your Experience¶
Kubernetes certificates (CKA exam):
# Generate user key
openssl genrsa -out user.key 2048
# Create CSR
openssl req -new -key user.key -out user.csr -subj "/CN=user/O=group"
# Sign with cluster CA
openssl x509 -req -in user.csr \
-CA /etc/kubernetes/pki/ca.crt \
-CAkey /etc/kubernetes/pki/ca.key \
-CAcreateserial -out user.crt -days 365
# Create kubeconfig
kubectl config set-credentials user --client-certificate=user.crt --client-key=user.key
Jenkins/Nginx HTTPS (same process!):
# Generate server key
openssl genrsa -out jenkins.key 4096
# Create CSR
openssl req -new -key jenkins.key -out jenkins.csr
# Submit to Let's Encrypt (or any CA)
sudo certbot --csr jenkins.csr
# Install in Nginx
sudo cp jenkins.key /etc/ssl/private/
sudo cp fullchain.pem /etc/ssl/certs/
THE PROCESS IS IDENTICAL - SAME CRYPTOGRAPHY, DIFFERENT USE CASE!