Nginx Webserver mit PHP

Einleitung

Nginx ist ein leistungsfähiger, leichtgewichtiger und hoch skalierbarer Webserver. Nginx ist bekannt für seine Effizienz und Geschwindigkeit. Die Konfiguration von Nginx erfolgt über einfache, gut strukturierte Konfigurationsdateien. Die Syntax ist klar und leicht verständlich, was die Administration und Anpassung erleichtert. FreeBSD bietet eine hervorragende Basis für den Betrieb eines Nginx Webserver.

Ziele

Nginx bildet zusammen mit PHP den Webserver und damit die Grundlage für viele darauf aufbauenden Artikel.

NEU: Für ganz ungeduldige habe ich einen Konsole only Abschnitt. Da gibts nur Befehle, keine Erklärungen.

Letzte Aktualisierung:

  • 02.09.2024: Backup der Konfiguration ergänzt
  • 28.08.2024: Kleinigkeiten korrigiert und PHP 8.4 getestet
  • 10.03.2024: Um HTTPS und selbst signierte Zertifikate ergänzt
  • 03.03.2024: Initiales Dokument

Voraussetzungen

  • TrueNAS Core oder reiner FreeBSD Server mit installiertem iocage

Diagramm

Damit sieht das Setup inkl. aller optionalen Möglichkeiten so aus:

                   ┌────────────────────────────────────────────┐
                   │  TrueNAS            Optional:              │
                   │ ┌────────────────┐ ┌─────────────────────┐ │
                   │ │ jails/JAILNAME │ │ jails_data/JAILNAME │ │
                   │ │   php   ──┐    │ │                     │ │
LAN: 0.0.0.0:80  ──┼─┼─► nginx ──┴────┼─┼─► conf              │ │
                   │ └────────────────┘ └─────────────────────┘ │
                   └────────────────────────────────────────────┘

Jail erstellen

Es wird ein eigenes Jail benötigt, sollten auf Nginx/PHP weitere Web Applikationen aufbauen.
Hier nehmen wir web als Jail Namen.

Optional: Datenverzeichnisse

Dies ist eher für fortgeschrittenen Anwender gedacht, die schon etwas Erfahrung besitzen.

Wie bestimmte Datenverzeichnisse außerhalb des Jails abgelegt werden, wird hier erklärt.
Es werden folgende Verzeichnisse benötigt:

└── /mnt/tank/jails_data
    └── JAILNAME # Name des Jails, in welches der Webserver und PHP installiert werden soll
        └── conf # Ablage für Konfigurationsdateien (im Jail: /mnt/conf)

Jail einrichten

Login per SSH in das Jail: ssh USERNAME@IP oder ssh USERNAME@HOSTNAME, um mit su root Rechte zu erlangen.

Paketquelle anpassen

Paketquellen sollten angepasst werden, siehe separater Artikel.

Pakete installieren & Dienste aktivieren

Nun die Paketquelle mit pkg update aktualisieren und dann die benötigten Pakete installieren: pkg install -y nginx php84 php84-extensions

Konfiguration erstellen

Die Konfiguration wird zur besseren Übersicht in verschiedene Dateien aufgeteilt:
PHP-FPM und andere Applikationen kommen in ein eigenes Verzeichnis: mkdir /usr/local/etc/nginx/conf.d

  • /usr/local/etc/nginx/nginx.conf = Allgemeine Konfiguration
  • /usr/local/etc/nginx/conf.d/ = Ordner für weitere Konfigurationsdateien
  • /usr/local/etc/nginx/conf.d/php.conf = PHP in NGINX aktivieren

OPTIONAL: Symlinks setzen um auf die Konfiguration ggf. in /mnt/conf/ zu verweisen: ln -sf /mnt/conf/nginx.conf /usr/local/etc/nginx/nginx.conf
ln -sf /mnt/conf/php.conf /usr/local/etc/nginx/conf.d/php.conf
ln -sf /mnt/conf/dhparam.pem /usr/local/etc/nginx/dhparam.pem
ln -sf /mnt/conf/nginx.key /usr/local/etc/nginx/nginx.key
ln -sf /mnt/conf/nginx.crt /usr/local/etc/nginx/nginx.crt
ln -sf /mnt/conf/www.conf /usr/local/etc/php-fpm.d/www.conf

Zertifikat

Dienste sollten durch eine abgesicherte Verbindung aufgerufen werden, auch lokal.

Mit dem folgenden Befehl wird ein selbstsigniertes Zertifikat erzeugt. Das wird zwar im Browser (einmalig) eine Warnung erzeugen, sorgt aber für eine verschlüsselte Verbindung.

  • Diffie-Hellman parameter erstellen: openssl dhparam -out /usr/local/etc/nginx/dhparam.pem 4096
  • Das Zertifikat wird mit folgenden Parametern erstellt, gerne anpassen:
    
    C = Country Name (2 letter code) [AU]: DE
    ST = State or Province Name (full name) [Some-State]: NRW
    L = Locality Name (eg, city) []: ERKRATH
    O = Organization Name (eg, company) [Internet Widgits Pty Ltd]: BSDBOX
    OU = Organizational Unit Name (eg, section) []: IT
    CN = Common Name (e.g. server FQDN or YOUR name) []: rs.bsdbox.local

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 3650 -nodes -keyout /usr/local/etc/nginx/nginx.key -out /usr/local/etc/nginx/nginx.crt -subj "/C=DE/ST=NRW/L=ERKRATH/O=BSDBOX/OU=IT/CN=rss.bsdbox.local"


####  Nginx & PHP

```sh
cat > /usr/local/etc/nginx/nginx.conf << 'EOF'
worker_processes auto;
error_log /var/log/nginx-error.log;

events {
 worker_connections 1024;
 use kqueue;
 multi_accept on;
}

http {
 access_log /var/log/nginx/access.log;
 include mime.types;
 default_type application/octet-stream;

 sendfile on;
 tcp_nopush on;
 tcp_nodelay on;
 reset_timedout_connection on;
 keepalive_timeout 65;
 keepalive_requests 1000;
 types_hash_max_size 2048;
 send_timeout 30;
 server_names_hash_max_size 4096;

 gzip on;
 gzip_disable "msie6";
 gzip_vary on;
 gzip_proxied any;
 gzip_comp_level 6;
 gzip_buffers 16 8k;
 gzip_http_version 1.1;
 gzip_types application/javascript application/rss+xml application/vnd.ms-fontobject application/x-font application/x-font-opentype application/x-font-otf application/x-font-truetype application/x-font-ttf application/x-javascript application/xhtml+xml application/xml font/opentype font/otf font/ttf image/svg+xml image/x-icon text/css text/javascript text/plain text/xml;

 client_header_timeout 180s;
 client_body_temp_path /var/tmp/nginx/client_body_temp;

 ssl_certificate /usr/local/etc/nginx/nginx.crt; # RSA Cert
 ssl_certificate_key /usr/local/etc/nginx/nginx.key; # RSA Key
 ssl_dhparam /usr/local/etc/nginx/dhparam.pem; # 4096 Diffie-Hellman parameter

 proxy_buffer_size 4k;
 proxy_buffers 8 16k;
 proxy_busy_buffers_size 64k;
 proxy_temp_file_write_size 64k;
 proxy_temp_path /var/tmp/nginx/proxy_temp;
 proxy_cache_valid 1m;

 include /usr/local/etc/nginx/conf.d/*.conf;
}
'EOF'
cat > /usr/local/etc/nginx/conf.d/php.conf << 'EOF'
upstream php-handler {
 server unix:/var/run/php-fpm.sock;
}
'EOF'
cat > /usr/local/etc/php-fpm.d/www.conf << 'EOF'
[www]
user = www
group = www
listen = /var/run/php-fpm.sock
listen.owner = www
listen.group = www
listen.mode = 0660
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
'EOF'

PHP anpassen

PHP ist eine weit verbreitete Skriptsprache, die als Modul in einen Webserver integriert wird.
Als erstes wird die mitgelieferte Grundkonfiguration aktiviert: cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini

OPTIONAL: Symlinks setzen um auf die Konfiguration ggf. in /mnt/conf/ zu verweisen:
ln -sf /mnt/conf/99-custom.ini /usr/local/etc/php/99-custom.ini

In der /usr/local/etc/php.ini gibt es einige Optionen, die angepasst werden wollen. Das geht am übersichtlichsten mit einer eigenen ini-Datei.

cat > /usr/local/etc/php/99-custom.ini << 'EOF'
date.timezone = Europe/Berlin
post_max_size=16M
upload_max_filesize=16M
max_execution_time=300
max_input_time = 300
memory_limit=512M
display_errors=Off
expose_php=Off
register_globals=Off
file_uploads=On
allow_url_fopen=Off
disable_functions=show_source, system, shell_exec, proc_open, proc_nice
cgi.fix_pathinfo=0
'EOF'

Dienste starten

Dienste aktivieren und beim Start des Jails automatisch mit starten: service nginx enable && service php_fpm enable Damit sind wir nun am Ende der Vorbereitungen angelangt und alle Dienste können nun mit service php_fpm start && service nginx start gestartet werden.

Wichtig. Es gibt noch keine Server Sektion. Damit läuft zwar der Webserver, liefert aber keine Seiten aus. Also nicht wundern.

Backup

Die Konfiguration selber ist statisch und muss eigentlich nicht separat und vor allem nicht regelmäßig gesichert werden. Dieses Jail ist auch von Grund auf sehr schnell wieder aufgebaut. Vor allem dann nicht, wenn die Daten außerhalb des Jails liegen. Sollte dennoch das Bedürfnis nach einem Backup aufkommen, so lässt sich mit diesem Befehl schnell erledigen:

Manuell

tar -cpzhf /mnt/backup/conf_`date +%Y%m%d`.tar.gz /usr/local/etc/nginx /usr/local/etc/php-fpm.d /usr/local/etc/php

Automatisch

Hier in dem Beispiel werden die Verzeichnisse /usr/local/etc/nginx /usr/local/etc/php-fpm.d /usr/local/etc/php per Cron Job jeden Sonntag um 22 Uhr gesichert.
Das Entfernen von alten Backups wird mit einer Aufgabe für die Applikation später mit erledigt (z.B. bei FresRSS)

echo "# Config Backup" >> /etc/crontab
echo "0 22 * * 7 root "tar -cpzhf /mnt/backup/conf_'$(date +\%Y\%m\%d)'.tar.gz /usr/local/etc/nginx /usr/local/etc/php-fpm.d /usr/local/etc/php"" >> /etc/crontab

Konsole

OPTIONAL = Nur durchführen wenn die Konfiguration außerhalb des Jails liegt
INITIAL = Nur bei der Erstinstallation ausführen oder wenn die Konfiguration nicht außerhalb des Jails liegt

pkg install -y nginx php84 php84-extensions
mkdir /usr/local/etc/nginx/conf.d
OPTIONAL: ln -sf /mnt/conf/nginx.conf /usr/local/etc/nginx/nginx.conf
OPTIONAL: ln -sf /mnt/conf/php.conf /usr/local/etc/nginx/conf.d/php.conf
OPTIONAL: ln -sf /mnt/conf/dhparam.pem /usr/local/etc/nginx/dhparam.pem
OPTIONAL: ln -sf /mnt/conf/nginx.key /usr/local/etc/nginx/nginx.key
OPTIONAL: ln -sf /mnt/conf/nginx.crt /usr/local/etc/nginx/nginx.crt
OPTIONAL: ln -sf /mnt/conf/www.conf /usr/local/etc/php-fpm.d/www.conf
OPTIONAL: ln -sf /mnt/conf/99-custom.ini /usr/local/etc/php/99-custom.ini
INITIAL: fetch https://raw.githubusercontent.com/marzlberger/bsdbox/main/ngingx-php/nginx.conf -o /usr/local/etc/nginx/nginx.conf
INITIAL: fetch https://raw.githubusercontent.com/marzlberger/bsdbox/main/ngingx-php/99-custom.ini -o /usr/local/etc/php/99-custom.ini
INITIAL: fetch https://raw.githubusercontent.com/marzlberger/bsdbox/main/ngingx-php/php.conf -o /usr/local/etc/nginx/conf.d/php.conf
INITIAL: fetch https://raw.githubusercontent.com/marzlberger/bsdbox/main/ngingx-php/www.conf -o /usr/local/etc/php-fpm.d/www.conf
openssl dhparam -out /usr/local/etc/nginx/dhparam.pem 4096
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 3650 -nodes -keyout /usr/local/etc/nginx/nginx.key -out /usr/local/etc/nginx/nginx.crt -subj "/C=DE/ST=NRW/L=ERKRATH/O=BSDBOX/OU=IT/CN=rss.bsdbox.local"
cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
service nginx enable && service php_fpm enable
service php_fpm start && service nginx start

Voilá