How to Install SSL Certificate on Lighttpd Server
Lighttpd (pronounced “lighty”) is a lightweight, fast web server optimized for high-performance environments. This guide covers SSL/TLS certificate installation on Lighttpd, from basic setup to production-ready configuration.
Prerequisites
Before beginning, ensure you have:
- Lighttpd installed and running
- Root or sudo access
- A domain name pointing to your server
- SSL certificate files (or ability to obtain them)
Check Lighttpd version:
lighttpd -v
Understanding Lighttpd SSL Configuration
Unlike Nginx or Apache, Lighttpd requires certificates in a specific format:
- Combined PEM file: Certificate + private key + intermediate certificates in one file
- The order matters: private key → certificate → intermediate(s)
- File must have appropriate permissions (chmod 600)
Method 1: Self-Signed Certificate (Development Only)
For testing environments, generate a self-signed certificate.
Generate Self-Signed Certificate
# Create directory for certificates
sudo mkdir -p /etc/lighttpd/ssl
cd /etc/lighttpd/ssl
# Generate private key and certificate in one command
sudo openssl req -newkey rsa:2048 -nodes -keyout server.key \
-x509 -days 365 -out server.crt
# Combine into single PEM file (required by Lighttpd)
sudo cat server.key server.crt > server.pem
# Secure the file
sudo chmod 600 server.pem
sudo chown root:root server.pem
When prompted, provide:
- Country Name: Two-letter code (e.g., US, GB, PL)
- State: Full state/province name
- City: Full city name
- Organization Name: Your company
- Organizational Unit: Department (optional)
- Common Name: Your domain or IP (e.g., localhost, 192.168.1.1)
- Email: Contact email
Configure Lighttpd for SSL
Edit Lighttpd configuration:
sudo nano /etc/lighttpd/lighttpd.conf
Add or modify SSL configuration:
# Load SSL module
server.modules += ( "mod_openssl" )
# SSL Configuration
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/lighttpd/ssl/server.pem"
# Optional: Custom SSL settings
ssl.honor-cipher-order = "enable"
ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM"
ssl.use-sslv2 = "disable"
ssl.use-sslv3 = "disable"
}
# Redirect HTTP to HTTPS (optional)
$HTTP["scheme"] == "http" {
url.redirect = ("" => "https://${url.authority}${url.path}${qsa}")
}
Test and restart Lighttpd:
# Test configuration
sudo lighttpd -t -f /etc/lighttpd/lighttpd.conf
# Restart Lighttpd
sudo systemctl restart lighttpd
Method 2: Let’s Encrypt Certificate
For production sites, use free Let’s Encrypt certificates with automatic renewal.
Install Certbot
# Ubuntu/Debian
sudo apt update
sudo apt install certbot
# CentOS/RHEL
sudo yum install certbot
# Fedora
sudo dnf install certbot
Obtain Certificate
# Stop Lighttpd temporarily
sudo systemctl stop lighttpd
# Obtain certificate using standalone mode
sudo certbot certonly --standalone -d example.com -d www.example.com
# Or use webroot mode (Lighttpd can stay running)
sudo certbot certonly --webroot -w /var/www/html -d example.com -d www.example.com
Certificates are saved to /etc/letsencrypt/live/example.com/
Create Combined PEM File
Lighttpd requires private key and certificates in one file:
# Create combined PEM file
sudo cat /etc/letsencrypt/live/example.com/privkey.pem \
/etc/letsencrypt/live/example.com/cert.pem \
/etc/letsencrypt/live/example.com/chain.pem \
> /etc/lighttpd/ssl/example.com.pem
# Secure the file
sudo chmod 600 /etc/lighttpd/ssl/example.com.pem
sudo chown root:root /etc/lighttpd/ssl/example.com.pem
Configure Lighttpd for Let’s Encrypt
Edit /etc/lighttpd/lighttpd.conf:
server.modules += ( "mod_openssl" )
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/lighttpd/ssl/example.com.pem"
ssl.ca-file = "/etc/letsencrypt/live/example.com/chain.pem"
# Modern SSL/TLS settings
ssl.openssl.ssl-conf-cmd = ("Protocol" => "-ALL, TLSv1.2, TLSv1.3")
ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"
ssl.honor-cipher-order = "enable"
ssl.use-sslv2 = "disable"
ssl.use-sslv3 = "disable"
}
Restart Lighttpd:
sudo systemctl restart lighttpd
Automate Certificate Renewal
Create renewal hook script:
sudo nano /etc/letsencrypt/renewal-hooks/deploy/lighttpd.sh
Add content:
#!/bin/bash
DOMAIN="example.com"
PEM_FILE="/etc/lighttpd/ssl/${DOMAIN}.pem"
# Combine renewed certificates
cat /etc/letsencrypt/live/${DOMAIN}/privkey.pem \
/etc/letsencrypt/live/${DOMAIN}/cert.pem \
/etc/letsencrypt/live/${DOMAIN}/chain.pem \
> ${PEM_FILE}
# Set permissions
chmod 600 ${PEM_FILE}
chown root:root ${PEM_FILE}
# Restart Lighttpd
systemctl restart lighttpd
Make executable:
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/lighttpd.sh
Test renewal:
sudo certbot renew --dry-run
Method 3: Commercial SSL Certificate
For commercial certificates from DigiCert, GlobalSign, Sectigo, etc.
Step 1: Generate CSR and Private Key
# Create SSL directory
sudo mkdir -p /etc/lighttpd/ssl
cd /etc/lighttpd/ssl
# Generate private key
sudo openssl genrsa -out example.com.key 2048
# Generate CSR
sudo openssl req -new -key example.com.key -out example.com.csr
Provide accurate information when prompted:
- Common Name (CN): Your domain (example.com)
- Organization: Legal company name
- Organizational Unit: Department
- City/Locality: Full city name
- State/Province: Full state name
- Country: Two-letter code
Step 2: Submit CSR to Certificate Authority
# Display CSR
cat example.com.csr
Copy the entire CSR (including BEGIN and END lines) and submit to your CA. Complete domain validation.
Step 3: Download Certificate Files
You’ll receive:
- Primary certificate (
example.com.crt) - Intermediate certificate(s) (
intermediate.crtorca-bundle.crt) - Sometimes a root certificate
Step 4: Create Combined PEM File
# Combine private key, certificate, and intermediates
sudo cat example.com.key \
example.com.crt \
intermediate.crt \
> /etc/lighttpd/ssl/example.com.pem
# Secure the file
sudo chmod 600 /etc/lighttpd/ssl/example.com.pem
sudo chown root:root /etc/lighttpd/ssl/example.com.pem
Important: The order must be: private key → certificate → intermediate(s)
Step 5: Configure Lighttpd
Edit /etc/lighttpd/lighttpd.conf:
server.modules += ( "mod_openssl" )
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/lighttpd/ssl/example.com.pem"
# Optional: Add CA bundle if separate
# ssl.ca-file = "/etc/lighttpd/ssl/ca-bundle.crt"
}
Restart Lighttpd:
sudo lighttpd -t -f /etc/lighttpd/lighttpd.conf
sudo systemctl restart lighttpd
Production-Ready SSL Configuration
Optimal Lighttpd SSL Settings
server.modules += (
"mod_openssl",
"mod_redirect"
)
# Enable compression (optional but recommended)
server.modules += ( "mod_deflate" )
deflate.cache-dir = "/var/cache/lighttpd/compress/"
deflate.mimetypes = ("text/html", "text/plain", "text/xml", "text/css", "text/javascript", "application/javascript")
# SSL Configuration for port 443
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/lighttpd/ssl/example.com.pem"
ssl.ca-file = "/etc/lighttpd/ssl/chain.pem"
# Modern TLS configuration
ssl.openssl.ssl-conf-cmd = ("Protocol" => "-ALL, TLSv1.2, TLSv1.3")
# Strong cipher suites
ssl.cipher-list = "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"
# Server cipher preference
ssl.honor-cipher-order = "enable"
# Disable old protocols
ssl.use-sslv2 = "disable"
ssl.use-sslv3 = "disable"
# OCSP Stapling (Lighttpd 1.4.56+)
ssl.ocsp-responder = "http://ocsp.example.com/"
# Diffie-Hellman parameters
ssl.dh-file = "/etc/lighttpd/ssl/dhparam.pem"
# HSTS header
setenv.add-response-header = (
"Strict-Transport-Security" => "max-age=31536000; includeSubDomains; preload"
)
}
# Redirect HTTP to HTTPS
$HTTP["scheme"] == "http" {
url.redirect = ("" => "https://${url.authority}${url.path}${qsa}")
url.redirect-code = 301
}
Generate DH Parameters
sudo openssl dhparam -out /etc/lighttpd/ssl/dhparam.pem 2048
sudo chmod 600 /etc/lighttpd/ssl/dhparam.pem
Virtual Hosting with Multiple SSL Certificates
For hosting multiple SSL sites on one server:
# Default SSL configuration
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
}
# Site 1: example.com
$HTTP["host"] == "example.com" {
ssl.pemfile = "/etc/lighttpd/ssl/example.com.pem"
ssl.ca-file = "/etc/lighttpd/ssl/example.com-chain.pem"
server.document-root = "/var/www/example.com"
}
# Site 2: another.com
$HTTP["host"] == "another.com" {
ssl.pemfile = "/etc/lighttpd/ssl/another.com.pem"
ssl.ca-file = "/etc/lighttpd/ssl/another.com-chain.pem"
server.document-root = "/var/www/another.com"
}
Note: Requires SNI (Server Name Indication) support, which is standard in modern browsers.
Troubleshooting
Lighttpd Won’t Start After SSL Configuration
Check error logs:
sudo tail -f /var/log/lighttpd/error.log
Common issues:
- PEM file wrong format or order
- Incorrect file permissions
- mod_openssl not loaded
- Port 443 already in use
“SSL: error:0906D06C:PEM routines”
Problem: PEM file format issue
Solution: Verify PEM file structure:
# Check PEM file
cat /etc/lighttpd/ssl/example.com.pem
# Should contain (in order):
# -----BEGIN PRIVATE KEY-----
# (private key data)
# -----END PRIVATE KEY-----
# -----BEGIN CERTIFICATE-----
# (certificate data)
# -----END CERTIFICATE-----
# -----BEGIN CERTIFICATE-----
# (intermediate certificate data)
# -----END CERTIFICATE-----
Recreate if needed:
sudo cat privkey.pem cert.pem chain.pem > combined.pem
Browser Shows “ERR_SSL_PROTOCOL_ERROR”
Checks:
# Verify Lighttpd is listening on 443
sudo netstat -tlnp | grep :443
# Check firewall
sudo ufw status
sudo ufw allow 443/tcp
# Test SSL handshake
openssl s_client -connect localhost:443
Certificate Chain Issues
Problem: “Incomplete certificate chain” warning in browser
Solution: Ensure intermediate certificates are included:
# Verify certificate chain
openssl s_client -connect example.com:443 -showcerts
Include all intermediates in PEM file:
cat privkey.pem cert.pem intermediate.pem root.pem > complete.pem
Security Best Practices
File Permissions
# PEM files should be readable only by root chmod 600 /etc/lighttpd/ssl/*.pem chown root:root /etc/lighttpd/ssl/*.pemDisable Old Protocols
ssl.use-sslv2 = "disable" ssl.use-sslv3 = "disable" ssl.openssl.ssl-conf-cmd = ("Protocol" => "-ALL, TLSv1.2, TLSv1.3")Strong Ciphers Only
ssl.cipher-list = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384" ssl.honor-cipher-order = "enable"Enable HSTS
setenv.add-response-header = ( "Strict-Transport-Security" => "max-age=31536000; includeSubDomains" )Monitor Certificate Expiration
- Use CrtMgr for automated monitoring
- Set up alerts 30 days before expiration
- Test renewal processes regularly
Testing Your SSL Configuration
Command Line Tests
# Test SSL connection
openssl s_client -connect example.com:443 -servername example.com
# Check certificate expiration
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
# Verify certificate chain
openssl s_client -connect example.com:443 -servername example.com -showcerts
# Test TLS versions
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3
Online Tools
Test your configuration:
- SSL Labs: https://www.ssllabs.com/ssltest/
- Security Headers: https://securityheaders.com/
- High-Tech Bridge: https://www.htbridge.com/ssl/
Lighttpd-Specific Testing
# Check configuration syntax
lighttpd -t -f /etc/lighttpd/lighttpd.conf
# Debug mode (verbose output)
lighttpd -D -f /etc/lighttpd/lighttpd.conf
# Check loaded modules
lighttpd -f /etc/lighttpd/lighttpd.conf -p
Performance Optimization
Enable SSL Session Caching
Lighttpd 1.4.56+ supports session caching:
ssl.openssl.ssl-conf-cmd = ("Options" => "SessionTicket")
Enable HTTP/2
For modern clients:
server.modules += ( "mod_openssl" )
$SERVER["socket"] == ":443" {
ssl.engine = "enable"
ssl.pemfile = "/etc/lighttpd/ssl/example.com.pem"
# Enable HTTP/2 (Lighttpd 1.4.56+)
server.feature-flags += ("server.h2proto" => "enable")
}
Compression
Enable compression for better performance:
server.modules += ( "mod_deflate" )
deflate.cache-dir = "/var/cache/lighttpd/compress/"
deflate.mimetypes = (
"text/html",
"text/plain",
"text/xml",
"text/css",
"text/javascript",
"application/javascript",
"application/json"
)
Monitoring and Maintenance
Monitor Certificate Expiration
Use CrtMgr to track your Lighttpd certificates:
- Add your domain to CrtMgr
- Configure expiration alerts
- Set up public status pages
- Receive timely notifications
Or create a monitoring script:
#!/bin/bash
DOMAIN="example.com"
WARN_DAYS=30
# Get expiration date
EXPIRY=$(echo | openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
# Calculate days remaining
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))
echo "Certificate for $DOMAIN expires in $DAYS_LEFT days"
if [ $DAYS_LEFT -lt $WARN_DAYS ]; then
echo "WARNING: Certificate expiring soon!"
# Send alert
fi
Regular Maintenance Tasks
- Update Lighttpd regularly
- Review security advisories
- Test configuration after updates
- Rotate logs
- Check certificate validity monthly
Conclusion
Installing SSL certificates on Lighttpd is straightforward once you understand the PEM file requirement. Key points:
- Combine files: Private key + certificate + intermediates in one PEM
- Correct order: Private key first, then certificate, then chain
- Secure permissions: chmod 600 for PEM files
- Modern protocols: TLS 1.2 and 1.3 only
- Monitor expiration: Use CrtMgr or similar tools
With proper configuration, Lighttpd provides fast, secure HTTPS connections with minimal resource usage. Its lightweight nature makes it perfect for high-performance scenarios while maintaining strong security.
Regular monitoring with tools like CrtMgr ensures your certificates stay valid, preventing unexpected outages and maintaining user trust.