OCSP Stapling Configuration: Apache and Nginx
OCSP (Online Certificate Status Protocol) stapling improves TLS handshake performance and privacy by allowing servers to fetch and cache certificate status responses. Instead of clients querying the OCSP responder, servers include the status response in the TLS handshake. This guide covers OCSP fundamentals, server configuration, and verification.
Table of Contents
- Prerequisites
- Understanding OCSP Stapling
- OCSP Responder Details
- Nginx OCSP Stapling
- Apache OCSP Stapling
- Certificate Status Validation
- Monitoring OCSP
- Troubleshooting
- Performance Considerations
- Conclusion
Prerequisites
Before implementing OCSP stapling, ensure you have:
- Web server (Nginx 1.3.7+ or Apache 2.4+)
- SSL certificates from CA with OCSP support
- OpenSSL installed
- Root or sudo access
- Understanding of certificate status verification
Understanding OCSP Stapling
Traditional certificate status checking:
Client OCSP Responder
| |
+-- TLS handshake ----------> Server
|
+-- Verify certificate ------->
| (Is cert revoked?)
+-- Query OCSP responder ------> OCSP Responder
| |
|<------ OCSP response -----------+
Drawbacks:
- Extra latency (separate OCSP query)
- Privacy leak (OCSP responder sees client identity)
- Single point of failure (OCSP responder down)
OCSP stapling:
Client Server OCSP Responder
| | |
|<-- TLS handshake --+ |
| + OCSP response (cached) |
| | |
| +-- Fetch OCSP status -->
| | |
| |<-- OCSP response -----+
| | (cached for reuse)
Benefits:
- Faster: No client OCSP query needed
- Private: OCSP responder doesn't see client
- Reliable: Server-side failure doesn't affect clients
- Backward compatible: Works with clients that don't support OCSP stapling
OCSP Responder Details
Find OCSP responder URL in certificate:
openssl x509 -in cert.pem -text -noout | grep -A1 "OCSP"
Output example:
Authority Information Access:
OCSP - URI:http://ocsp.lets-encrypt.org/v1
Query OCSP manually:
# Extract issuer certificate
openssl x509 -in fullchain.pem -text -noout | grep -A1 "Issuer:"
# Get OCSP responder URL
OCSP_URL=$(openssl x509 -in cert.pem -ocsp_uri -noout)
# Query OCSP
openssl ocsp -no_nonce -issuer chain.pem -cert cert.pem \
-header "HOST" "ocsp.lets-encrypt.org" \
-url "$OCSP_URL"
OCSP response example:
cert.pem: good
This Update: Jan 15 10:00:00 2024 GMT
Next Update: Jan 22 10:00:00 2024 GMT
Nginx OCSP Stapling
Configure Nginx to fetch and cache OCSP responses.
Nginx configuration with OCSP stapling:
server {
listen 443 ssl http2;
server_name example.com;
# SSL certificates
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# OCSP cache file
ssl_stapling_file /var/cache/nginx/ocsp.staple;
# Trust store for OCSP response verification
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# OCSP responder timeout
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;
}
Create cache directory:
sudo mkdir -p /var/cache/nginx
sudo chown nginx:nginx /var/cache/nginx
sudo chmod 755 /var/cache/nginx
Test configuration:
sudo nginx -t
sudo systemctl reload nginx
Verify OCSP stapling is enabled:
openssl s_client -connect example.com:443 -servername example.com -ocsp
Look for:
OCSP response:
======================================
OCSP response status: successful (0x0)
Alternative configuration with resolver:
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;
# OCSP stapling with resolver
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# Resolver configuration
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 10s;
# OCSP cache
ssl_stapling_file /var/cache/nginx/ocsp-example.staple;
# Automatic OCSP update every 6 hours
ssl_stapling_responder http://ocsp.lets-encrypt.org/v1;
}
Apache OCSP Stapling
Configure Apache to fetch and cache OCSP responses.
Apache configuration with OCSP stapling:
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
# OCSP stapling
SSLUseStapling on
SSLStaplingCache shmcb:/var/run/ocsp-stapling.cache(128000)
# Responder timeout
SSLStaplingResponderTimeout 5
# Verify OCSP response
SSLStaplingReturnResponderErrors off
# Force stapling
SSLStaplingForcedRenew on
</VirtualHost>
Enable required modules:
sudo a2enmod ssl
sudo a2enmod socache_shmcb
sudo systemctl reload apache2
Test Apache configuration:
sudo apache2ctl configtest
Verify OCSP stapling:
openssl s_client -connect example.com:443 -servername example.com -ocsp
Apache configuration with status caching:
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# OCSP stapling with shared memory cache
SSLUseStapling on
SSLStaplingCache shmcb:/var/run/apache2/ssl_stapling_cache(512000)
# Update interval (in seconds)
SSLStaplingStandardCacheTimeout 3600
SSLStaplingErrorCacheTimeout 600
# Responder URL (auto-detected from certificate)
SSLStaplingResponderTimeout 5
</VirtualHost>
Certificate Status Validation
Validate that OCSP stapling is working correctly.
Check OCSP response in TLS handshake:
# Detailed output
openssl s_client -connect example.com:443 \
-servername example.com \
-ocsp \
</dev/null 2>/dev/null | grep -A 20 "OCSP response"
Verify OCSP response signature:
# Extract OCSP response from server
openssl s_client -connect example.com:443 \
-servername example.com \
-tlsextdebug </dev/null 2>&1 | grep -A 5 ocsp_response
# Validate response
openssl ocsp -respin ocsp_response.der \
-inform DER \
-issuer chain.pem \
-cert cert.pem \
-verify_other chain.pem \
-text
Test with curl:
# Show response metadata
curl -vI https://example.com 2>&1 | grep -i ocsp
# Verbose TLS debug
curl -v --tlsv1.2 https://example.com 2>&1 | grep -i ocsp
Monitoring OCSP
Monitor OCSP status and caching effectiveness.
Nginx OCSP monitoring:
# Check cache file
ls -lah /var/cache/nginx/ocsp.staple
stat /var/cache/nginx/ocsp.staple
# Monitor OCSP fetch
curl -v https://example.com 2>&1 | grep -i ocsp
Apache OCSP monitoring:
# Check shared memory cache
ipcs | grep ssl
# Monitor Apache logs
tail -f /var/log/apache2/access.log | grep ocsp
tail -f /var/log/apache2/error.log
# Check SSLStaplingCache
apache2ctl fullstatus | grep -i ocsp
Create monitoring script:
#!/bin/bash
# check-ocsp-stapling.sh
DOMAIN=$1
PORT=${2:-443}
echo "Checking OCSP stapling for $DOMAIN:$PORT"
# Get OCSP response
RESPONSE=$(openssl s_client -connect $DOMAIN:$PORT \
-servername $DOMAIN \
-ocsp </dev/null 2>&1)
# Check if OCSP stapling is present
if echo "$RESPONSE" | grep -q "OCSP response status: successful"; then
echo "✓ OCSP stapling: ENABLED"
echo "✓ Status: SUCCESSFUL"
exit 0
elif echo "$RESPONSE" | grep -q "OCSP response:"; then
echo "✓ OCSP stapling: ENABLED"
echo "⚠ Status: $(echo "$RESPONSE" | grep 'OCSP response status' | head -1)"
exit 0
else
echo "✗ OCSP stapling: DISABLED"
exit 1
fi
Run:
./check-ocsp-stapling.sh example.com 443
Troubleshooting
OCSP stapling not working:
# Verify certificate has OCSP responder
openssl x509 -in cert.pem -text -noout | grep -A1 "OCSP"
# Check if OCSP responder is reachable
curl -I http://ocsp.lets-encrypt.org/v1
# Verify Nginx/Apache can access responder
nc -zv ocsp.lets-encrypt.org 80
Nginx configuration issues:
# Check syntax
nginx -t -c /etc/nginx/nginx.conf
# Verify stapling settings
grep -A5 "ssl_stapling" /etc/nginx/nginx.conf
# Check cache directory permissions
ls -la /var/cache/nginx/
# Test manually
openssl ocsp -no_nonce -issuer chain.pem -cert cert.pem \
-url "http://ocsp.lets-encrypt.org/v1"
Apache configuration issues:
# Check syntax
apache2ctl configtest
# Verify modules loaded
apache2ctl -M | grep ssl
apache2ctl -M | grep socache
# Check shared memory cache
ipcs -m
# Clear cache if needed
apache2ctl graceful
OCSP responder timeout:
# Increase timeout in configuration
# Nginx: resolver_timeout 10s;
# Apache: SSLStaplingResponderTimeout 10
# Test responder speed
curl -w "Total: %{time_total}s\n" http://ocsp.lets-encrypt.org/v1
Performance Considerations
OCSP stapling impact on performance:
Fetch strategy:
- Periodic fetch (recommended): Server fetches at intervals
- On-demand fetch: Fetched when needed
Caching:
- Staple cache: Server caches response locally
- Duration: Typically 1-7 days based on CA settings
Performance benefits:
Without OCSP stapling:
- Client TLS handshake: ~100ms
- Client OCSP query: ~50-200ms (additional)
- Total: ~150-300ms
With OCSP stapling:
- Server TLS handshake: ~100ms (includes cached OCSP)
- No client OCSP query
- Total: ~100ms
Optimization settings:
# Nginx cache configuration
ssl_stapling_file /var/cache/nginx/ocsp.staple;
# Resolver with caching
resolver 8.8.8.8 valid=300s;
resolver_timeout 5s;
# Apache cache configuration
SSLStaplingCache shmcb:/var/run/ocsp(512000)
SSLStaplingResponderTimeout 5
SSLStaplingStandardCacheTimeout 3600
Conclusion
OCSP stapling improves TLS handshake performance and privacy by having servers deliver cached certificate status responses. This guide covered OCSP fundamentals, configuration in Nginx and Apache, status validation, and monitoring. For production deployments, enable OCSP stapling on all servers, monitor cache effectiveness, ensure OCSP responders are reachable, and test configurations regularly. OCSP stapling is a critical performance optimization for any TLS-enabled service.


