Oleksandr Gavenko's blog
2017-01-25 01:30 Setting Let’s Encrypt in Lighttpd

Tonight I'll show how to set Let's Encrypt for Lighttpd.


Let's Encrypt is a free, automated, and open Certificate Authority.

Serving site via HTTP means that user interaction with server can be intercepted, studied, altered.

If you are prompted to enter password on HTTP page most probably it will be send in clear text through HTTP...

Browsers have ability to secure interaction with user. It is described by SSL/TSL standards.

Unfortunately during time of creation of these standards they dealt with another problem - how user can trust server. It is resolved with using certificates.

Certificated are ordered in chain of trust. Certificate issuers ask browser vendors to include their root certificates in browser distribution. Root certificates are trusted by default.

Certificate issuers sell signatures for site certificates and site owner embeds this certificate with signature into a web servers.

Browser gets site owner's certificate with issuer's signature along with HTML pages. Browser checks if issuer is known and included in trusted database and if all OK it decides to trust to site and to establish encrypted connection with a server.

While authentication of server is a good thing call for secured communication is more important nowadays.

It is possible to establish secure connection between server and browser without selling signatures but industry stuck with specific historical implementation and can't move further.

Let’s Encrypt project bring encryption to historical implementations by supplying site owners with free of cost SSL/TSL certificates.

Their root certificate is already included in all major browsers and software distributions certificate stores. Of cause this root certificate marked as weak and have only intention to establish encryption between points.

Let’s Encrypt organization performs basic checks before singing your certificate - do you own domain name and server behind that domain name.

They developed a protocol to automate issuing of certificate signatures.

certbot is client that implement that protocol.


Automatically enable HTTPS on your website with EFF's Certbot, deploying Let's Encrypt certificates.

It is available in Debian repositories:

$ sudo apt install python-certbot

certbot designed to be extensible via plug-ins but at this moment there is no plug-in for Lighttpd. Although there is generic method implemented in webroot plug-in that provide automatic updated of certificates.

webroot plug-in put special files into you site web root directory under /.well-known/ sub-directory and Let’s Encrypt service expect to find that file under HTTP /.well-known/ path to be shure that you are domain/site owner.

Cron job for lighttpd and certbot is:


# -q  quiet
# -n  do not prompt
#  --webroot  plugin
certbot certonly -n --expand --webroot \
  -w /srv/www/base/ -d defun.work \
  -w /srv/www/blog/ -d blog.defun.work \
  -w /srv/www/resume/ -d resume.defun.work \
  -w /srv/hg/ -d hg.defun.work



cat $privkey $cert >$server_pem
cat $chain >$chain_pem

service lighttpd restart

Paths to certificates is defined in one of:

$ cat /etc/letsencrypt/renewal/defun.work.conf

# renew_before_expiry = 30 days
version = 0.9.3
cert = /etc/letsencrypt/live/defun.work/cert.pem
privkey = /etc/letsencrypt/live/defun.work/privkey.pem
chain = /etc/letsencrypt/live/defun.work/chain.pem
fullchain = /etc/letsencrypt/live/defun.work/fullchain.pem

# Options used in the renewal process
authenticator = webroot
installer = None
account = XXXXXX
webroot_path = /srv/www/base, /srv/www/blog, /srv/www/resume, /srv/hg
resume.defun.work = /srv/www/resume
defun.work = /srv/www/base
hg.defun.work = /srv/hg
blog.defun.work = /srv/www/blog

Configuration for static site hosting by lighttpd looks like:

$ cat /etc/lighttpd/conf-available/92-resume.conf

$HTTP["host"] == "resume.defun.work" {
  server.document-root = "/srv/www/resume"

Configuration for SSL:

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

$SERVER["socket"] == "" {
  ssl.engine  = "enable"
  ssl.pemfile = "/etc/lighttpd/server.pem"
  ssl.ca-file = "/etc/lighttpd/chain.pem"

  ssl.cipher-list = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:!RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM"
  ssl.honor-cipher-order = "enable"

The only problem I had was with GCI hosted Mercurial.

I added exception in activation of CGI, any request to /.well-known/ is hosted as file resource:

$ cat /etc/lighttpd/conf-available/92-hgweb.conf

$HTTP["host"] == "hg.defun.work" {
  server.document-root = "/srv/hg"
  url.rewrite-once = (
    "/static/avatar/(.*)" => "/$1",
    "/.well-known.*" => "$0",
    "^/?(.*)" => "/hgweb.cgi/$1",
  $HTTP["url"] !~ "^/.well-known" {
    cgi.assign = ( "/hgweb.cgi" => "" )
  setenv.add-environment = ( "HGWEB_CONFIG" => "/srv/hg/hgweb.config" )
  dir-listing.activate = "disable"
  index-file.names = ()

Let’s Encrypt issues single SAN (Subject Alternative Name) certificate and with modern browsers this allows serving virtual hosts via HTTPS even from single IP.

See also:


Certbot manual on usage.


SSL on multiple domains.


How To Set Up Multiple SSL Certificates on One IP with Lighttpd.

That's all for this night!

UPDATE. Some old mobile browser report that sertificate is not valid.

You can figure out problems with your site certificate via online service:


My site missed intermidiate certificate. It's due to Let's Encrypt is not in trusted storage of old programs. As workaround Let's Encrypt have signature from DST Root CA X3 which is already in trusted storages.

In order to pass that intermidiate / chain certificate I should tell Lighttpd where it is:

ssl.ca-file = "/etc/lighttpd/chain.pem"

See also:


Request for combined priv/pub certificate for Lighttpd.


Docs about support of intermidiate/chain certificate in Lighttpd.


Page for testing Let's Encrypt certificate in real browser.


List of supported by Let's Encrypt certificate clients.


List of supported by Let's Encrypt certificate clients.

security, lighttpd, admin, web


all / emacs / java


adb(1), admin(1), android(1), anki(1), ansible(2), blog(2), c(1), css(2), cygwin(2), driver(1), emacs(3), fs(1), git(3), google(1), gradle(1), hardware(1), hg(2), html(1), interview(13), java(3), js(3), lang(2), lighttpd(1), markdown(1), mobile(1), naming(1), oracle(1), print(1), problem(5), python(1), quiz(6), rst(2), security(3), spring(1), sql(2), srs(1), style(1), tls(2), txt(1), unit(1), utils(1), vcs(3), web(2), win(2), windows(1)