Lighttpd, PHP-FPM, Let's Encrypt mit Multidomains

Published on 2018-05-07 by Malte

Im folgenden Artikel möchte ich erklären, wie man eine Webserver Umgebung mit PHP-FPM und Let's Encrypt Zertifikaten mit dem Webserver Lighttpd (lighty) umsetzen kann. Die folgende Konfiguration führt dazu, dass ihr bei folgenden Tests, eine A(+) bekommt:

Hinweis: Ein natürlicher Menschenverstand wird vorausgesetzt, bitte nicht einfach blind kopieren!

Installation

Als erstes installieren wir die benötigt Software:

apt install lighttpd php-fpm certbot

Konfiguration

lighttpd - PHP-FPM

Im folgenden werden wir lighttpd konfigurieren. Als erstes sorgen wir dafür das lighttpd mit PHP-FPM umgehen kann, dazu gehen wir in den Ordner ***/etc/lighttpd/conf-available/***.

Dort werden wir jetzt die Datei 15-fastcgi-php.conf bearbeiten, und folgenden Inhalt einfügen:

# -*- depends: fastcgi -*-
# /usr/share/doc/lighttpd/fastcgi.txt.gz
# http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ConfigurationOptions#mod_fastcgi-fastcgi

## Start an FastCGI server for php (needs the php5-cgi package)
fastcgi.server += ( ".php" =>
        ((
                "socket" => "/var/run/php/php7.2-fpm.sock",
                "broken-scriptfilename" => "enable"
        ))
)

Umbedingt den Socket Pfad kontrollieren! Jetzt sagen wir lighttpd er soll das Modul laden:

lighttpd-enable-mod fastcgi
lighttpd-enable-mod fastcgi-php
service lighttpd force-reload

Jetzt kann lighttpd mit PHP Dateien umgehen.

lighttpd

Im folgenden werden wir lighttpd konfigurieren. Dazu bearbeiten wir die Datei /etc/lighttpd/lighttpd.conf und fügen folgenden Inhalt hinzu:

server.modules = (
        "mod_access",
        "mod_alias",
        "mod_compress",
        "mod_redirect",
        )
#default webseite
server.document-root        = "/var/www/html/kiefer-networks.de/"
server.upload-dirs          = ( "/var/cache/lighttpd/uploads" )
server.errorlog             = "/var/log/lighttpd/error.log"
server.pid-file             = "/var/run/lighttpd.pid"
server.username             = "www-data"
server.groupname            = "www-data"
server.port                 = 80
#Server Tag ist der Name der angezeigt wird beim Abtasten des Servers (Nginx v.234)
server.tag                  = "Mein Server"


index-file.names            = ( "index.php", "index.html", "index.lighttpd.html" )
#Zugriff auf folgende Dateien untersagen
url.access-deny             = ( "~", ".inc" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )

compress.cache-dir          = "/var/cache/lighttpd/compress/"
compress.filetype           = ( "application/javascript", "text/css", "text/html", "text/plain" )

# default listening port for IPv6 falls back to the IPv4 port
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"

#Wir erlauben nur das die HTTP Requests Methoden GET & POST erlaubt sind

$HTTP["request-method"] !~ "^(GET|POST)" {
    url.access-deny = ("")
}

#Setzten der entsprechenden HTTP Headers, Achtung CSP anpassen

server.modules += ( "mod_setenv" )
$HTTP["scheme"] == "https" {
    setenv.add-response-header  = (
            "Content-Security-Policy"   => "default-src 'self'; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; img-src 'self'; media-src 'self'; frame-src https://*.openstreetmap.org https://*.google.com; font-src https://fonts.googleapis.com; connect-src 'none'",
            "Strict-Transport-Security" => "max-age=15768000; includeSubDomains; preload",
            "X-Content-Type-Options" => "nosniff",
            "X-Frame-Options" => "DENY",
            "X-XSS-Protection" => "1; mode=block"
            )
}

#Umleiten von HTTP zu HTTPS

$HTTP["scheme"] == "http" {
    $HTTP["host"] =~ ".*" {
        url.redirect = (".*" => "https://%0$0")
    }
}

#Multi Webseiten Konfiguration

$HTTP["host"] =~ "(^|\.)example\.de$" {
    	server_name = "example.de"
        server.document-root = "/var/www/html/example.de" 
        server.errorlog = "/var/log/lighttpd/ex_de_error.log"	
}

$HTTP["host"] =~ "(^|\.)example\.com$" {
    	server_name = "example.com"
        server.document-root = "/var/www/html/example.com" 
        server.errorlog = "/var/log/lighttpd/ex_com_error.log"	
}

lighttpd SSL Konfiguration

Jetzt werden wir noch die SSL Konfiguration anpassen. Dazu bearbeiten wir die Datei /etc/lighttpd/conf-available/10-ssl.conf. Wir passen den Inhalt wir folgt an:

$SERVER["socket"] == ":443" {
    protocol     = "https://"
        ssl.engine   = "enable"
        ssl.disable-client-renegotiation = "enable"
        ssl.pemfile = "/etc/lighttpd/ssl/example.de.pem" 
        ssl.ca-file = "/etc/lighttpd/ssl/fullchain.pem"

        ssl.ec-curve              = "secp384r1"

        setenv.add-environment = (
                "HTTPS" => "on"
                )
        ssl.use-sslv2 = "disable"
        ssl.use-sslv3 = "disable"
        ssl.honor-cipher-order    = "enable"
        ssl.cipher-list           = "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"

        $HTTP["host"] =~ "(^|\.)example\.de$" {
            ssl.pemfile = "/etc/lighttpd/ssl/example.de.pem"
            ssl.ca-file = "/etc/lighttpd/ssl/fullchain.pem"
        }


    	$HTTP["host"] =~ "(^|\.)example\.com$" {
        	ssl.pemfile = "/etc/lighttpd/ssl/example.com.pem"
            ssl.ca-file = "/etc/lighttpd/ssl/fullchain.pem"
    	}
}

Dazu erstellen wir noch den folgenden Ordner

mkdir /etc/lighttpd/ssl/

Jetzt noch das SSL Modul aktivieren

lighttpd-enable-mod ssl
service lighttpd restart

Let's Encrypt

Bei lighttpd gibt es eine Besonderheit bei den Zertifikaten, so muss der Private Schlüssel und das Zertifikate in einer Datei sein und das CA immer als Referenz mit angebenen sein. Damit wir das nicht für jede Datei einzeln machen müssen, werden wird ein fertiges Script nehmen, was sich auch darum kümmert, die Zertifikate aktuell zu halten.

Dazu wechseln wir nach /opt. Dann klonen wir folgenden Repo:

git clone https://github.com/galeone/letsencrypt-lighttpd.git

Wechselt in den neuen Ordner letsencrypt-lighttpd. Als erstes bearbeiten wir die Datei letsencrypt-lighttpd.service und passen den ExecStart an nach /opt/letsencrypt-lighttpd/renew.sh.

ExecStart=/opt/letsencrypt-lighttpd/renew.sh

Dann kopieren die Service Dateien und starten den Dienst:

cp letsencrypt-lighttpd.* /etc/systemd/system/
systemctl enable letsencrypt-lighttpd.timer

Jetzt der "schwierige" Teil, wir passen noch renew.sh an:

#!/usr/bin/env bash 
set -eu

#Domain sudomain part (mail.example.de => mail)
domain_subdomains=( \
#domain     sub sub sub
"example.de w ww www" \
"example.com w ww www" \
)
email=mail@example.de
w_root=/var/www/html/ #Speicherort der Webseiten
user=root
group=root

# end configuration

if [ "$EUID" -ne 0 ]; then
    echo  "Please run as root"
    exit 1
fi

for domain_set_string in "${domain_subdomains[@]}"; do
    domain_set=(${domain_set_string// / })
    domain=${domain_set[0]}
    unset domain_set[0]

    all_subdomains="-d $domain"
    if [ ${#domain_set[@]} -gt 0 ]; then
        for sub_domain in "${domain_set[@]}"; do
            all_subdomains="$all_subdomains -d $sub_domain.$domain"
        done
    fi

    /usr/bin/certbot certonly --agree-tos --renew-by-default \
        --rsa-key-size 4096 --email $email --webroot -w $w_root$domain \
        $all_subdomains
    cat /etc/letsencrypt/live/$domain/privkey.pem \
        /etc/letsencrypt/live/$domain/cert.pem \
        > /etc/lighttpd/ssl/$domain.pem
    cp /etc/letsencrypt/live/$domain/fullchain.pem \
       /etc/lighttpd/ssl/
    chown -R $user:$group /etc/lighttpd/
	chmod 600 /etc/lighttpd/*.pem
done

Hinweis: Die Webseiten müssen im Ordner /var/www/html/ gespeichert werden, im Format der angegebenen Domain: /var/www/html/example.de

Jetzt starten wir die Dienste neu:

service php7.2-fpm restart
service lighttpd restart

Dann lassen wir uns noch die Zertifikate austellen

bash /opt/letsencrypt-lighttpd/renew.sh

Fazit

Der Lighttpd ist ein leistungsstarker Server, der wunderbar ein Ersatz für nginx und Apache sein kann.