Error message

Deprecated function: The each() function is deprecated. This message will be suppressed on further calls in menu_set_active_trail() (line 2404 of /usr/share/drupal7/includes/menu.inc).

Secure Web Connection with Lighttpd + Let’s Encrypt = A+ score on ssllabs (HTTPS + HSTS)

Lighttpd + Let’s Encrypt + This HOWTO = A+ score on ssllabs (HTTPS + HSTS)
My A+ report: https://www.ssllabs.com/ssltest/analyze.html?d=geeky.name&s=188.166.188.226
ssllabs A+ rating for geeky.name

Synopsis

sudo apt install letsencrypt openssl
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
Create /etc/lighttpd/conf-available/99-letsencrypt.conf
Enable config and restart Lighttpd
sudo letsencrypt certonly --webroot -w /var/www/ -d [YOUR_DOMAIN_NAME]
Merge /etc/letsencrypt/live/[YOUR_DOMAIN_NAME]/combined.pem
Edit /etc/lighttpd/conf-available/10-ssl.conf
Enable config and restart Lighttpd
Edit /etc/crontab

What is HTTPS 1

HTTP 2

HTTPS 1

SSL and TLS 3

Tools

  • letsencrypt 4
  • openssl
  • lighttpd

sudo apt install lighttpd letsencrypt openssl

Steps

Prepare Information

Settle Files

You can find all files in my gist https://gist.github.com/bluet/ee521743fa0da703af68f37ac0f63a90

1. Enhance DH Key Exchange parameters

/etc/ssl/certs/dhparam.pem sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

2. Let's Encrypt authentication URL

/etc/lighttpd/conf-available/99-letsencrypt.conf

alias.url += (
    "/.well-known/acme-challenge/" => "/var/www/.well-known/acme-challenge/"
)

Enable it sudo lighty-enable-mod letsencrypt sudo service lighttpd restart

3. Obtain certs

Remeber to replace [YOUR_DOMAIN_NAME] to your domain name. sudo letsencrypt certonly --webroot -w /var/www/ -d [YOUR_DOMAIN_NAME] Follow it's instructions, type in your email and accept agreement.
If you want to apply for multiple domain, just append more -d some.domain.name after the original command.

4. Prepare PEM for Lighttpd

cat /etc/letsencrypt/live/[YOUR_DOMAIN_NAME]/privkey.pem \
/etc/letsencrypt/live/[YOUR_DOMAIN_NAME]/cert.pem \
> /etc/letsencrypt/live/[YOUR_DOMAIN_NAME]/combined.pem

5. Update Lighttpd config

/etc/lighttpd/conf-available/10-ssl.conf

server.modules += ("mod_setenv")      # For HSTS

$SERVER["socket"] == "0.0.0.0:443" {
    ssl.engine  = "enable"

    ssl.pemfile = "/etc/letsencrypt/live/[YOUR_DOMAIN_NAME]/combined.pem"
    ssl.ca-file = "/etc/letsencrypt/live/[YOUR_DOMAIN_NAME]/fullchain.pem"
    ssl.dh-file = "/etc/ssl/certs/dhparam.pem"
    ssl.ec-curve = "secp384r1"
    ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"
    ssl.honor-cipher-order = "enable"
    ssl.use-sslv2 = "disable"
    ssl.use-sslv3 = "disable"
    ssl.use-compression     = "disable"
    setenv.add-response-header = (
        "Strict-Transport-Security" => "max-age=63072000; includeSubDomains; preload",
        "X-Frame-Options" => "SAMEORIGIN",
        "X-Content-Type-Options" => "nosniff"
    )
    setenv.add-environment = (
        "HTTPS" => "on"
    )
}

If you have IPv6, also append the following config at the button of /etc/lighttpd/conf-available/10-ssl.conf

$SERVER["socket"] == "[::]:443" {   # For IPv6
    # ...Same setting as above...
}

Enable it sudo lighty-enable-mod ssl sudo service lighttpd restart

5. Setup auto-renew

letsencrypt-renew.lighttpd.sh

#!/bin/bash

YOUR_DOMAIN_NAME="www.example.com"

letsencrypt renew \
&& cat /etc/letsencrypt/live/$YOUR_DOMAIN_NAME/privkey.pem /etc/letsencrypt/live/$YOUR_DOMAIN_NAME/cert.pem > /etc/letsencrypt/live/$YOUR_DOMAIN_NAME/combined.pem \
&& service lighttpd reload

Append cron setting in /etc/crontab

0 4     * * 6   root    /usr/local/bin/letsencrypt-renew.lighttpd.sh

Confirm and Enjoy

Go https://www.ssllabs.com/ssltest/index.html check your site.

Hope this HOWTO can save a tree and a kitten.


FYI

Corner Case

Different cert for specific domain (virtual host)

If you want to use different cert files for specific domain, just create a new .conf in /etc/lighttpd/conf-available/, and enable it with lighty-enable-mod.

$HTTP["host"] == "[YOUR_DOMAIN_NAME]" {
    server.document-root = [YOUR_SITE_CONTENT_FOLDER]
    # ...Same setting as above...
}

Proxy All except .well-known

If you're proxying all requests for a domain, you need this to exclude .well-known path.

$HTTP["host"] == "proxied.example.com" {
        alias.url += (
                "/.well-known/acme-challenge/" => "/var/www/.well-known/acme-challenge/"
        )
        $HTTP["url"] !~ "^/.well-known/acme-challenge/" {
                proxy.balance = "hash"
                proxy.server  = ( "" => (
                        ( "host" => "1.2.3.4", "port" => "8080" ),
                ) )
        }
}

Attachments

https://gist.github.com/BlueT/ee521743fa0da703af68f37ac0f63a90

Reference


  1. https://en.wikipedia.org/wiki/HTTPS ↩︎ ↩︎

  2. https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol ↩︎

  3. https://en.wikipedia.org/wiki/Transport_Layer_Security ↩︎

  4. https://letsencrypt.org/ ↩︎

Add new comment