ACME without NGINX on NixOS

ACME is fantastically well integrated into NGINX on NixOS, but how do you use it without having NGINX installed? On most of my systems I just include NGINX, because, why not. But if you don't want to have a full webserver running, e.g. for a VPN using port 443, what do you do?

As it turns out, all you need is something like this, using lighttpd to simply serve a webroot on port 80, and the ACME client normally used by NixOS:

{
  services.lighttpd = {
    enable = true;
    port = 80;
    document-root = "/srv/www";
  };

  system.activationScripts.create-srv-dir = ''
    echo "ensuring ${config.services.lighttpd.document-root}" exists...
    mkdir -p ${config.services.lighttpd.document-root}
  '';

  security.acme = {
    certs.${config.networking.domain} = {
      webroot = "/srv/www";
      email = "you@example.com";
    };
  };
}

You can still use the web root on port 80 if you want to, either way you should see that there is a .well-known directory under it, which is 403 forbidden if you try and access it via HTTP.

If you need to pull the generated keys out for use elsewhere, you can add the following field to the acme expression:

{
  security.acme.certs."${config.networking.domain}".allowKeysForGroup = true;
}

This chmods the certificates 750 rather than 700 to allow group access, so the other service you want to use the certificate with must share the same group.

After ACME is run, the paths to the generated certificates can be found under:

/var/lib/acme/${config.networking.domain}/key.pem
/var/lib/acme/${config.networking.domain}/fullchain.pem
/var/lib/acme/${config.networking.domain}/full.pem

Of which the ones you'll most likely want to use are the key, key.pem and the certificate, fullchain.pem.