I'm trying to set up letsencrypt on lighttpd from scratch. I currently run lighttpd on 16.10 xenial and want to move over existing sites to https from http. I know there's an automatic setup process for Apache and ngnix, but I'm disinclined to move things over. I have half a dozen hostnames, over a pair of domains hosted using virtualhosts, and with individual blocks per host.

How would I do this?


Most tools support a "dumb webserver" mode, in which they provide files that need to be served by your webserver in the /.well-known/acme-challenge/ directory.

It is also possible to generate that content with some dynamic language (lua, php, ...: concat the request filename, '.' and the public key hash)


It took a bit of trial and error, and throwing together bits from multiple sources.

You might wish to do a few things differently depending on your needs. In this case I haven't done a few things people include, and a few things are optional.

I started off with this guide, and diverged wildly

If you want to generate your own ssl.dh-file do it now. Its optional and takes a while

cd /etc/ssl/certs


openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096 is slow, and somewhat redundant openssl dhparam -dsaparam -out etc/ssl/certs/dhparam.pem is a lot faster

Next, install letsencrypt's certbot according to the instructions

$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install certbot

Generate your certs. I chose to have one cert for all my hosts in the "example.com" domain on one cert and have "example.org" on its own cert.

certbot uses your web server ports so shut down your lighttpd instance first

Generating a cert is simply a matter of running

certbot certonly --standalone -d example.org for one domain and certbot certonly --standalone -d example.com -d chat.example.com for multiple domains (up to 20) in a cert.

lighttpd expects a single pem file, and letsencrypt does a pair (initially!) so, you'll need to merge them. Go to cd /etc/letsencrypt/live/ go into each folder and run cat privkey.pem cert.pem > ssl.pem

For our purposes, lets assume you have files in "/etc/letsencrypt/live/chat.example.com/" and "/etc/letsencrypt/live/example.org/"

For testing purposes lets assume you want one of these certs as a default, and you want to keep port 80 available for testing to see if the server starts with your changes.

Add a block reading

$SERVER["socket"] == ":443" {
    ssl.engine                  = "enable"
    ssl.pemfile                 = "/etc/letsencrypt/live/chat.example.com/ssl.pem"
    ssl.ca-file                 = "/etc/letsencrypt/live/chat.example.com/fullchain.pem"


You can replace this later, and is the bare minimum and lets you run https alongside http.

Any host without an explicit set of settings connecting to https will use these certs. Its a minimal viable set to test on.

Start lighttpd and test.

Now, If you're serious you may want more settings, like using that ssl.dh setting we talked about, and you spent two hours generating a dhparam.pem file for right at the start.You can replace the block you just added with something like this - this acts as default settings for the whole server.

$SERVER["socket"] == ":443" {
ssl.engine                  = "enable"
ssl.pemfile                 = "/etc/letsencrypt/live/chat.example.com/ssl.pem"
ssl.ca-file                 = "/etc/letsencrypt/live/chat.example.com/fullchain.pem"
ssl.dh-file                 = "/etc/ssl/certs/jmg2dhparam.pem"
ssl.ec-curve                = "secp384r1"
ssl.honor-cipher-order      = "enable"
ssl.cipher-list             = "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"
ssl.use-compression         = "disable"

$HTTP["scheme"] == "http" {
    # capture vhost name with regex conditiona -> %0 in redirect pattern
    # must be the most inner block to the redirect rule
    $HTTP["host"] =~ ".*" {
        url.redirect = (".*" => "https://%0$0")

It does HTTPS with a fuller set of settings (adjust to taste) and redirects any HTTP connections to HTTPS.

If you want a domain with a different set of keys you can override these settings in the host block.

$HTTP["host"] =~ "(^|\.)example\.org$" {
server.document-root = "/var/www/example"
server.errorlog = "/var/log/lighttpd/example/error.log"
accesslog.filename = "/var/log/lighttpd/example/access.log"
server.error-handler-404 = "/e404.php"
ssl.pemfile                 = "/etc/letsencrypt/live/example.org/ssl.pem"
ssl.ca-file                 = "/etc/letsencrypt/live/example.org/fullchain.pem"

Restart your server, test to make sure port 80 isn't connectable, and https is, and you should be good.

  • The downside of this approach should be clear, but let me say it anway: having to shutdown your real webserver and running a "replacement" which doesn't serve the real content just to get new certificates every 3 months is a really bad idea. – Stefan Apr 4 '17 at 5:40
  • True, but this seems to be the way most people are doing it. And the setup on the web server side for multiple domains/subdomains with ssl isn't really documented in one place. I'm still trying to work out renewals, but its something I can throw into a maintenance window fairly painlessly. Yeah, it could be better, but better is switching web servers in this case. – Journeyman Geek Apr 4 '17 at 5:46

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.