This document is archived and may be out of date or inaccurate.


A guide to configuring a static web server using Lighttpd on CentOS 7


This is currently in ‘recipe’ format and doesn’t explain why or go into depth. Future plan for this doc is to be more detailed in those areas.

What you get

  • Web Server
    • Static virtual hosting
    • Let’s Encrypt SSL certificates
  • Admin
    • Some attack reduction and blocking

Not in this document

Future work

  • Add alternate path for web app support (e.g. CGI, uwSGI, etc).

Out of scope (i.e. lots of other documentation sources for these)

  • Initial host/instance setup
  • General admin utilities and convenience setup


  • An internet accessible host
  • DNS Service (such as, self-hosted, etc)
  • For this HOWTO: CentOS 7, 1 GiB RAM, 10 GiB HD (e.g. virtual HD)
  • Repos
    • Defaults + EPEL (to install epel do yum install epel-release)


The following packages need to be installed for this setup (e.g. yum install package1 package2 …)

Admin tools

  • policycoreutils
  • policycoreutils-python
  • rsync

Web server

  • httpd-tools
  • lighttpd

Let’s Encrypt / ACME SSL certificates

  • certbot

Attack detection / blocking

  • fail2ban
  • fail2ban-firewalld
  • fail2ban-server

First steps

  1. Configure networking,admin users etc for your host/instance
  2. (Optional) Install your preferred admin/monitoring utilities etc.
  3. Install “Admin Tools” listed above
  4. Add ‘EPEL’ repository listed above

Web server & Let’s Encrypt configuration

If you are not serving web pages or apps other Certbot configuration might be more suitable for getting Let’s Encrypt SSL certificates for your mail server.

Web server (HTTP: only serves ACME / Let’s Encrypt verification)

  1. Install “Web Server” packages above

  2. In file /etc/lighttpd/lighttpd.conf

    1. below
      var.vhosts_dir = server_root + "/vhosts"
      var.vhosts_acme_dir = server_root + "/vhosts-acme"

    2. At end, add:

      $HTTP["scheme"] == "http" {
      include "/etc/lighttpd/vhosts-acme.d/*.conf"
  3. Configure IP binding

    1. Uncomment the server.bind = “localhost” line and replace localhost with your hostname (e.g.
    2. Below it add $SERVER["socket"] == "" { }. Optionally replace with your ipv4 address.
  4. In file, /etc/lighttpd/conf.d/dirlisting.conf

    1. set dir-listing.activate to “disable” (unless you want a browse-able list of files and directories for directories without an index file).
  5. In file, /etc/lighttpd/modules.conf

    1. inside the directive server.modules =, uncomment or add the following:

      • mod_alias,
      • mod_redirect,
    2. if you want to redirect to, after the closing parentheses for server-modules add

      $HTTP["scheme"] == "http" {
          $HTTP["host"] == "" {
              url.redirect = (".*" => "$0")
    3. Uncomment include “conf.d/compress.conf”

    4. Execute mkdir -p /var/cache/lighttpd/compress

    5. Perform restorecon -Rv /var/cache/lighttpd

  6. For each static virtual host to serve, under /etc/lighttpd/vhosts-acme.d/ include a file such as (NB: The filename must end in .conf):

    $HTTP["host"] == "" {
      var.server_name = "" = server_name
      server.document-root = vhosts_acme_dir + "/"
      accesslog.filename = log_root + "/" + server_name + "/access.log"
  7. Issue setsebool -P httpd_setrlimit on

  8. In /etc/lighttpd/lighttpd.conf set server.max-connections=512
    or set
    server.max-fd=2048 (depending on traffic and resources)

  9. Run lighttpd-angel -t -f /etc/lighttpd/lighttpd.conf and correct any errors detected.

  10. Execute systemctl restart lighttpd

  11. Do systemctl enable --now lighttpd

Web server (HTTPS: the real servers; requires SSL)

Prerequisites: Installed and configured web server as above.

Let’s encrypt (Part 1)

  1. Install “Let’s Encrypt” package above (certbot)

  2. Add certbot user and group

    adduser -U --system -M certbot
    passwd -l certbot
  3. Add renew-hooks deploy script directory

    mkdir -p /etc/letsencrypt/renewal-hooks/deploy && chown -R certbot:certbot /etc/letsencrypt
  4. Place the following script in /etc/letsencrypt/renewal-hooks/deploy as lighttpd and make it executable NOTE With newer lighttpd this is not required as lighttpd now supports separate certificate and key files

        cd /etc/letsencrypt/live/${CERTBOT_DOMAIN} && cat fullchain.pem privkey.pem >lighttpd.pem && chmod 640 lighttpd.pem || RET=1
    exit $RET
  5. Place the following script in /etc/cron.daily as certbot and make it executable

    /bin/su -c "certbot -q -n renew" certbot
  6. Issue mkdir -p /var/lib/letsencrypt && chown certbot:certbot /var/lib/letsencrypt

  7. Do mkdir -p /var/log/letsencrypt && chown certbot:adm /var/log/letsencrypt

  8. Perform certbot register

Lighttpd configuration (Part 2)

  1. Create ACME / Let’s Encrypt verification directories (these will be internet accessible from per-vhost directories down (e.g. in the example below will be the web root))

    mkdir -p /var/www/vhosts-acme/
    chown -R certbot:certbot /var/www/vhosts-acme/
  2. Repeat for each vhost you want to enable

  3. Issue

    firewall-cmd --add-service http
    firewall-cmd --add-service https
    firewall-cmd --runtime-to-permanent

Let’s Encrypt (Part 2)

  1. Issue

    su - certbot
    certbot certonly --staging --webroot -w /var/www/vhosts-acme/ -d -d
  2. If the command completes successfully, repeat the certbot command, without –staging.

  3. Issue

    cd /etc/letsencrypt/live/\<default-domain> # In the example above \<default-domain> is
    cat fullchain.pem privkey.pem >lighttpd.pem
    chmod 640 lighttpd.pem

    Note that Certbot recommendation is to put all hostnames on one certificate (see certbot –help –webroot for more information), unless one has specific reasons for having separate certificates. If you need separate certificates than you will need to issue the commands above for each certificate or set of certificates.

Lighttpd configuration (Part 3)

  1. In /etc/lighttpd/lighttpd.conf, before

    $HTTP["scheme"] == "http" {
      include "/etc/lighttpd/vhosts-acme.d/*.conf"

    which you added previously, add

    $SERVER["socket"] == "" { include "ssl.conf" }
    $SERVER["socket"] == "[::]:443" { include "ssl.conf" }
  2. Add a file /etc/lighttpd/ssl.conf that looks like:

    ssl.engine = "enable"
    ssl.pemfile = "/etc/letsencrypt/live/"
    include "/etc/lighttpd/vhosts.d/*.conf"
  3. And add a file /etc/lighttpd/vhosts.d/ for each virtual host you are adding (in this case that looks like:

    $HTTP["host"] == "" {
      var.server_name = "" = server_name
      server.document-root = vhosts_dir + "/"
      accesslog.filename = log_root + "/" + server_name + "/access.log"
  4. In file /etc/lighttpd/modules.conf

    1. inside the directive server.modules =, uncomment or add the following

    2. And if you want to use HTTP authentication for some pages or sites, also uncomment or add the following

      • "mod_auth",
      • "mod_authn_file",
    3. If you want to redirect HTTP to HTTPS, before

      $HTTP["scheme"] == "http" {
        $HTTP["host"] == "" {
          url.redirect = (".*" => "$0")

      which you added above, add

      $HTTP["scheme"] == "http" {
        $HTTP["host"] == "" {
          url.redirect = (".*" => "$0")

      and after, add

      $HTTP["scheme"] == "http" {
        $HTTP["url"] !~ "^/.well-known/acme-challenge/" {
          $HTTP["host"] =~ ".*" {
            url.redirect = ( "^/(.*)" => "https://%0/$1" )
  5. If you uncommented/added an mod_auth* line, make sure /etc/lighttpd/conf.d/auth.conf is all commented out

  6. If you want to require HTTP authentication for a page or site

    1. in /etc/vhosts.d/<host-to-require-auth>, above the closing brace (}) in the <host>.conf listed previously, add something similar to:

      auth.backend = "htdigest"
      auth.backend.htdigest.userfile = "/etc/lighttpd/users/\<host>"
      auth.require = ( "/" =>
          "method" => "digest",
          "realm" => "[auth-realm]",
          "require" => "valid-user"
    2. Use htdigest to create /etc/lighttpd/users/<host> (man htdigest for details)

  7. Do mkdir -p /var/www/vhosts/ for each static vhost you are creating.

DNS Setup

  • Add a DNS A record for your ‘base hostname’ (e.g. for with <your-ip>).
  • Add a DNS CNAME record for any virtual hosts (e.g. for add a CNAME record pointing to
  • Your bare domain name (e.g. should be A or AAAA records and not CNAMEs. This also helps if you move some subdomains, or the top level domain and some subdomains to services like Netlify.

Attack detection/blocking

  1. Install “Attack Detection/Blocking” packages listed above

  2. Create /etc/fail2bain/jail.local like the following:

    port = ssh,\<your-alternate-ssh-port-if-applicable> filter = sshd-aggressive enabled = true
    port = ssh, enabled = true
    enabled = true
    enabled = true
  3. Run touch /var/log/fail2ban.log

  4. And finally execute systemctl enable --now fail2ban