Linux Certificate Management
A comprehensive OpenSSL command reference, system trust store management, Let's Encrypt automation, and web server SSL configuration for Linux.
OpenSSL Reference
Generate keys
Generate a 2048-bit RSA key:
openssl genrsa -out server.key 2048Generate a 4096-bit RSA key with passphrase:
openssl genrsa -aes256 -out server.key 4096Generate a CSR
Create a CSR from an existing key:
openssl req -new -key server.key -out server.csr \
-subj "/CN=example.com/O=MyOrg/C=US/ST=California/L=San Francisco"Self-signed certificate
Generate a self-signed certificate with SANs:
openssl req -x509 -new -nodes \
-key server.key \
-sha256 -days 365 \
-out server.crt \
-subj "/CN=example.com/O=MyOrg/C=US" \
-addext "subjectAltName=DNS:example.com,DNS:www.example.com,IP:10.0.0.1" \
-addext "keyUsage=digitalSignature,keyEncipherment" \
-addext "extendedKeyUsage=serverAuth"View and verify certificates
Display certificate details:
openssl x509 -in server.crt -text -nooutVerify a certificate against a CA:
openssl verify -CAfile ca.crt server.crtVerify a chain with an intermediate:
openssl verify -CAfile ca.crt -untrusted intermediate.crt server.crtPKCS#12 operations
Create a PKCS#12 (PFX) file:
openssl pkcs12 -export \
-in server.crt \
-inkey server.key \
-certfile ca.crt \
-out server.pfx \
-name "myserver"Extract certificate and key from PKCS#12:
# Extract certificate
openssl pkcs12 -in server.pfx -clcerts -nokeys -out server.crt
# Extract private key
openssl pkcs12 -in server.pfx -nocerts -nodes -out server.keyCheck a remote server
Connect to a server and display its certificate:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -text -nooutCheck certificate expiry of a remote server:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -datesShow the full chain returned by the server:
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/nullSystem Trust Store
Linux distributions store trusted CA certificates in different locations and use different update commands.
Debian / Ubuntu
Add a custom CA certificate:
# Copy to the trusted CA directory
sudo cp myca.crt /usr/local/share/ca-certificates/myca.crt
# Update the trust store
sudo update-ca-certificates# Trusted store location
/etc/ssl/certs/ # Symlinks to trusted certs
/usr/local/share/ca-certificates/ # Where you add custom CAs
/etc/ssl/certs/ca-certificates.crt # Bundle used by most appsRHEL / CentOS / Fedora
Add a custom CA certificate:
# Copy to the trust anchors directory
sudo cp myca.crt /etc/pki/ca-trust/source/anchors/myca.crt
# Update the trust store
sudo update-ca-trustTip
The certificate file must be in PEM format (Base64 encoded, starting with -----BEGIN CERTIFICATE-----) and have a .crt extension.
Certbot (Let's Encrypt)
Install certbot:
# Ubuntu/Debian
sudo apt update && sudo apt install certbot
# With Nginx plugin
sudo apt install python3-certbot-nginx
# With Apache plugin
sudo apt install python3-certbot-apacheObtain a certificate (standalone mode):
sudo certbot certonly --standalone -d example.com -d www.example.comObtain a certificate with Nginx plugin:
sudo certbot --nginx -d example.com -d www.example.comRenew all certificates:
sudo certbot renewTest renewal without actually renewing:
sudo certbot renew --dry-runAdd a post-renewal hook to reload the web server:
sudo certbot renew --deploy-hook "systemctl reload nginx"Certbot stores certificates at /etc/letsencrypt/live/example.com/ with symlinks to the current version:
/etc/letsencrypt/live/example.com/
fullchain.pem # Certificate + intermediate chain
privkey.pem # Private key
cert.pem # Certificate only
chain.pem # Intermediate chain onlyNginx SSL Configuration
Nginx HTTPS server block:
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Modern TLS settings
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;
# HSTS
add_header Strict-Transport-Security "max-age=63072000" always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
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;
server_name example.com;
return 301 https://$host$request_uri;
}Apache SSL Configuration
Apache HTTPS virtual host:
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# Modern TLS settings
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLHonorCipherOrder off
# HSTS
Header always set Strict-Transport-Security "max-age=63072000"
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:5000/
ProxyPassReverse / http://127.0.0.1:5000/
</VirtualHost>
# Redirect HTTP to HTTPS
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>Warning
Ensure mod_ssl, mod_headers, and mod_proxy are enabled: sudo a2enmod ssl headers proxy proxy_http.
Checking a Remote Certificate
Quick one-liner to check a site's certificate expiry:
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
| openssl x509 -noout -subject -issuer -datesTest TLS connection with specific protocol:
openssl s_client -connect example.com:443 -tls1_3 </dev/nullDownload and save a remote certificate:
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
| openssl x509 -out remote.crt