FreeBSD 12 & Nginx & Kirby CMS

von nikken, erstellt am und zuletzt aktualisiert am .
CC0 Public Domain keine rechte vorbehalten.

Damit ich nicht jedes Mal von Neuem suchen und zusammenpuzzlen muss (Quellen s.u.), wie man sein PHP CMS mit TLS usw. usf. aufsetzt, habe ich hier mal alle Schritte (Disclaimer: funktioniert so für mich, für die angegebenen Versionen) aufgelistet.

Nachdem ich meinen Server eingerichtet habe (in diesem Fall einen VPS mit FreeBSD 12) gehe ich erstmal sicher, dass mein System auf dem aktuellen Stand ist und installiere danach alle nötigen Pakete.

# freebsd-update fetch install
# pkg update && pkg upgrade -y
# pkg install -y sudo bash vim-console unzip wget \
    nginx py37-certbot py37-certbot-nginx php73 \
    php73-extensions php73-mbstring php73-curl \
    php73-ctype php73-gd php73-json php73-filter

Um zu vermeiden, dass ich auf dem Server alles als root machen muss, erstelle ich meinen eigenen Nutzer, füge ihn der wheel-Gruppe hinzu und editiere die sudo-config dahingehend, dass Nutzer der wheel-Gruppe alle Befehle ausführen dürfen. Alsdann wechsle ich zu meinem neuen User und stelle die Zeitzone ein.

# adduser
    ...
    group: wheel
    ...
# visudo
    # uncomment %wheel ALL=(ALL) ALL
# su - $USER
$ sudo tzsetup

Weil Kirby ein PHP Programm ist, muss ich jetzt die lokale PHP und PHP-FPM Installation konfigurieren. Insbesondere muss ich dem FPM-Service sagen, dass er auf einem UNIX-Socket zuhören soll und welchen Nutzer- und Zugriffsrechten er unterliegt.

$ sudo ln -s /usr/local/etc/php.ini-production /usr/local/etc/php.ini
$ sudo vim /usr/local/etc/php-fpm.d/www.conf
    ...
    listen = 127.0.0.1:9000 -> listen = /var/run/php73-fpm.sock
    ...

    # uncomment:
    listen.owner = www
    listen.group = www
    listen.mode = 0660

Ist das erledigt, aktiviere ich den php_fpm-Service mit sysrc, sodass er beim Server-Neustart automatisch angeschmissen wird.

$ sudo sysrc php_fpm_enable=yes
$ sudo service php-fpm start

Das gleiche mache ich dann schonmal mit Nginx, bevor es dann an die eigentlichen Einstellungen geht:

$ sudo sysrc nginx_enable=yes
$ sudo service nginx start

Hierfür erstelle ich ein permanentes Verzeichnis für die Website und gebe meinem Nutzer Zugriffsrechte darauf.

$ sudo mkdir -p /usr/local/www/$DOMAIN
$ sudo chown -R $USER:$GROUP /usr/local/www/$DOMAIN

Weil ich einige Anläufe und Hilfe aus dem Kirby-Forum dafür gebraucht habe, um die Config hinzubekommen, schreibe ich sie hier mal komplett hin, in der Hoffnung, dass es irgendjemand (im Zweifel ich) nützlich finden könnte.

Insbesondere leitet diese Config allen HTTP-Verkehr auf HTTPS um (weiter unten richte ich dafür noch Let's Encrypt ein), setzt einige Rewrite-Regeln fest und konfiguriert das fastcgi.

$ sudo vim /usr/local/etc/nginx/$DOMAIN.conf

server {
    listen 80;
    listen [::]:80;
    return 301 https://$DOMAIN$request_uri;
}

server {
    listen 443 ssl default_server;
    listen [::]:443 ssl;
    server_name $DOMAIN www.$DOMAIN;

    ssl on;

    ssl_certificate /usr/local/etc/letsencrypt/live/$DOMAIN/fullchain.pem;
    ssl_certificate_key /usr/local/etc/letsencrypt/live/$DOMAIN/privkey.pem;

    root /usr/local/www/$DOMAIN;

    index index.html index.php;

    # don't hint these as folders
    rewrite ^/(content|site|kirby)$ /error last;

    # block content
    rewrite ^/content/(.*).(txt|md|mdown)$ /error last;

    # block all files in the site and kirby folder from being accessed directly
    rewrite ^/(site|kirby)/(.*)$ /error last;

    # site links
    location / {
        try_files $uri $uri/ /index.php?$uri&$args;
    }

    # prevent clients from accessing to backup/config/source files
    location ~ (?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$ {
        deny all;
    }

    location ~ \.php$ {
        try_files $uri = 404;
        fastcgi_pass unix:/var/run/php73-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Damit die Config auch gelesen wird, muss ich jetzt noch include $DOMAIN.conf; in den http-Block der Original-nginx.conf schreiben.

Let's Encrypt hat es innerhalb von kurzer Zeit möglich gemacht, dass man einfach, kostenlos und automatisiert den Verkehr zu seinem Webserver mit TLS verschlüsseln kann. Es gehört mittlerweile zum guten Ton, das in jedem Fall zu tun, auch wenn http ausreichen würde. Da mein CMS aber eine Login-Funktion hat und also Benutzerdaten und Passwörter über die Leitungen geschickt werden, will ich meinen Traffic auf jeden Fall verschlüsseln.

certbot ist das offizielle Skript von Let's Encrypt, das die Automatisierung der ganzen Zertifikats-Angelegenheiten möglich macht. Hier noch eine kleine FreeBSD-Besonderheit, auf die ich erstmal kommen musste: dort heißt nicht nur das Paket certbot-36 sondern auch die Binary. (Anm. 2019-09-14: Anscheinend ist dem nicht mehr so! Die folgenden Anweisungen habe ich unten entsprechend korrigiert. Anm. 2020-04-24: Der Port heißt jetzt py37-certbot und ist um einiges aktueller. Das Upgrade geschieht aber nicht von selbst, also py36-certbot* deinstallieren, py37-certbot{-nginx} installieren. Außerdem gibt es jetzt eine Konfiguration zum automatischen Aktualisieren in /etc/periodic.conf, nämlich weekly_certbot_enable="YES")

Die folgenden Zeilen erstellen dann Zertifikate für die beiden angegebenen Domains, testen im Trockenen ob das Erneuern auch funktioniert und erneuern sie.

$ sudo certbot certonly --webroot -w /usr/local/www/$DOMAIN -d $DOMAIN -d www.$DOMAIN
$ sudo certbot renew --dry-run
$ sudo certbot renew

Da die Let's Encrypt-Zertifikate nur ein paar Monate am Stück gültig sind, richten wir noch einen crontab ein, der in zufälligen Abständen unsere Zertifikate erneuert.

$ crontab -e
0 0,12 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew

Wenn bis hierhin alles gut gegangen ist, wird sich Nginx beim Testen der Config nicht beschweren und durch's Neustarten setzen wir alle Änderungen in Kraft.

$ sudo nginx -t
$ sudo service nginx reload

Jetzt sind wir endlich da angekommen, wo wir die ganze Zeit hinwollten: wir können Kirby installieren! Dafür laden wir uns die neueste Version auf den PC, bauen unsere Website und benutzen dann unser liebstes sftp/scp-Tool (nicht vergessen, die ssh/ftp-daemons einzurichten!) um die Dateien in das Verzeichnis zu laden, das wir oben erstellt haben.

Sollte jetzt alles funktionieren, geben wir dem Webserver (bzw. dem Nutzer, der den Webserver ausführt) noch die Verfügung über das Verzeichnis.

$ sudo chown -R www:www /usr/local/www/$DOMAIN

Quellen