CrtMgr Blog - SSL/TLS Certificate Management Insights

Expert insights on SSL/TLS certificate management, types, deployment, and best practices

How to Install SSL Certificate on Lighttpd Server

Lighttpd SSL TLS Web Server Installation Guide

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.crt or ca-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

  1. File Permissions

    # PEM files should be readable only by root
    chmod 600 /etc/lighttpd/ssl/*.pem
    chown root:root /etc/lighttpd/ssl/*.pem
    
  2. Disable Old Protocols

    ssl.use-sslv2 = "disable"
    ssl.use-sslv3 = "disable"
    ssl.openssl.ssl-conf-cmd = ("Protocol" => "-ALL, TLSv1.2, TLSv1.3")
    
  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"
    
  4. Enable HSTS

    setenv.add-response-header = (
        "Strict-Transport-Security" => "max-age=31536000; includeSubDomains"
    )
    
  5. 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:

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:

  1. Add your domain to CrtMgr
  2. Configure expiration alerts
  3. Set up public status pages
  4. 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.

Related Articles