Nextcloud mit Nginx und PHP-FPM

Für Nextcloud stehen 2 verschiedene Docker Images bereit:
- mit Webserver (Apache2) und PHP-FPM (-apache-Tag, latest [Standard])
- PHP-FPM ohne Webserver (-fpm-Tag)
Grundlegend unterscheiden sich die Images darin, dass die Webserver-Version direkt an einem HTTP Port binden kann und Anfragen via HTTP/S annehmen kann. Sollte man einen eigenen Webserver / Proxy (z.B. nginx) davor stellen wollen, ist es eine künstliche Verkomplizierung den Apache2 im Container zu nutzen.
In diesem Beispiel wird gezeigt wie ein bereits funktionierender Nginx direkt mit dem PHP-FPM im Docker-Container verbunden wird.
Was ist PHP-FPM
Als FastCGI Process Manager sorgt dieser dafür, dass Anfragen via FastCGI beantwortet werden können. FPM verwaltet seine Kind-Prozesse (starten, stoppen) und verteilt Anfragen an diese.
Kommunikation Webserver & PHP-FPM
Alle Anfragen zwischen PHP-FPM und dem Webserver erfolgen über das FastCGI Protokoll. In diesem stehen beispielsweise die Informationen aus dem HTTP-Request, Nutzdaten (z.B. von einem POST), die URL und weitere relevante Informationen, je nachdem wie der Webserver konfiguriert ist.
Die Kommunikation erfolgt hierbei via Unix-Socket (lokale "Datei"), oder TCP-IP Socket (Port), wobei in dieser Anleitung beide Fälle der Konfiguration berücksichtigt werden sollen.
Grundsätzlich sieht die Kommunikation folgenderweise aus:

Der Browser fragt eine Datei beim Webserver an. Dieser erkennt, dass es sich z.B. um eine PHP-Datei handelt, oder gibt die Anfrage aufgrund von Rewrite-Rules an den PHP-FPM. Ein Beispiel für den letzten Fall sind Webseiten wo man nur Pfadangaben hat und die PHP-Datei nicht direkt im Pfad steht (z.B. ttp://my.domain/my/profile).
Der Webserver gibt die nötigen Informationen mittels fast-cgi an den Socket von PHP-FPM, welcher die Informationen an seinen Kind-Prozess gibt und dieser versteht, welche Datei er parsen (einlesen) und verarbeiten muss.
Nach der Bearbeitung wird die Ausgabe an den Webserver weitergegeben, etwaige Returncodes (z.B: 404, 401, 200) werden ebenfalls übergeben, sodass der Webserver diese mit dem Inhalt der Antwort an den Browser zurücksenden kann.
Diese Erklärung ist rudimentär und nicht vollumfänglich ;)
Docker-Compose für Nextcloud
# File: /src/docker/nextcloud/docker-compose.yml
version: '3'
services:
nextcloud:
container_name: nextcloud
image: nextcloud:22-fpm
volumes:
- /srv/docker/nextcloud/html/:/var/www/html/
# der Pfad ist für den Unix-Socket nötig, den nginx anfragt
- /srv/docker/nextcloud/run:/var/run/php/
# php-fpm Konfigurationen werden hier abgelegt:
# /srv/docker/nextcloud/config/php-fpm.d)
# WENN dieser Ordner eingehangen wird, müssen die Konfigurationsdateien
# bereits vorliegen, sonst startet der FPM Container NICHT!
# Weitere Informationen siehe unten (Anpassung der PHP Einstellungen)!
- /srv/docker/nextcloud/config/php-fpm.d:/usr/local/etc/php-fpm.d/
restart: always
# Logindaten liegen außerhalb der compose-datei
env_file: /srv/docker/nextcloud/config/env_nextcloud
networks:
default:
ipv4_address: 192.168.1.2
# wird für Caching verwendet
redis:
container_name: nextcloud_redis
image: redis:alpine
volumes:
- /srv/docker/nextcloud/redis_data:/data:rw
restart: unless-stopped
networks:
default:
ipv4_address: 192.168.1.3
# zur Entlastung des Servers kann die Cloud via Websocket auch pushen
# hierfür muss aber erst in Nextcloud die App notify_push installiert werden, sonst existiert die Binary zum starten nicht!
push:
container_name: nextcloud_push
image: nextcloud:22-fpm
volumes:
- /srv/docker/nextcloud/run:/var/run/php/
- /srv/docker/nextcloud/html/:/var/www/html/
restart: always
# credentials outside the data dir
env_file: /srv/docker/nextcloud/config/env_push
working_dir: /var/www/html/config
command: /var/www/html/custom_apps/notify_push/bin/x86_64/notify_push config.php
networks:
default:
ipv4_address: 192.168.1.4
networks:
default:
driver: bridge
ipam:
driver: default
config:
- subnet: 192.168.1.0/24
driver_opts:
com.docker.network.bridge.name: br_ncloud
Docker-Compose Environment File
Die Datei wird mittels env_file verlinkt und kann somit für Credentials oder jegliche Environment-Variable genutzt werden, die der Docker-Container unterstützt. Einfach mal bei Nextcloud schauen...
# Hier wird von einem existierenden MySQL-Server ausgegangen!
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud
MYSQL_PASSWORD=MY_SECRET_PASSWORD
# IP wird variieren, es wird davon ausgegangen, dass dieser auf dem Host läuft und somit auf seiner IP erreichbar ist. (127.0.0.1 klappt nicht, wenn die Cloud isoliert ist, weil der Container seine eigene 127.0.0.1 Adresse hat!!!)
MYSQL_HOST=192.168.1.1
# Admin Login
NEXTCLOUD_ADMIN_USER=nextcloud@my-domain.de
NEXTCLOUD_ADMIN_PASSWORD=MY_ADMIN_PASSWORD
# erlaubte Adressen um die Cloud aufzurufen (siehe Anpassungen der nginx Konfiguration)
NEXTCLOUD_TRUSTED_DOMAIN=cloud.example.com
Nginx Konfiguration
Hier bietet sich die Verwendung der offiziellen Dokumention an:
https://docs.nextcloud.com/server/latest/admin_manual/installation/nginx.html
Folgende Änderungen sind empfehlenswert. Dies ist keine vollständige Liste aller Parameter:
# Nicht benötigte Option auskommentieren! Eine darf aktiv sein. (Unix empfohlen)
upstream php-handler {
# Kommunikation mittels TCP
server 127.0.0.1:9000;
# Kommunikation via Unix-Socket (außerhalb des Containers verfügbar)
# Der Pfad /var/run/php/ ist nur im Container verfügbar, außerhalb ist es der Pfad gemäß der docker-compose.yml
# siehe /srv/docker/nextcloud/run:/var/run/php
server unix:/srv/docker/nextcloud/run/nc.sock;
}
server {
# http2 kann Probleme verursachen, ggf. deaktivieren
# festes Binden des Servers auf eine IP:Port Kombination
listen 1.2.3.4:443 ssl http2;
# wenn kein IPv6 vorhanden oder erwünscht, auskommentieren!
#listen [::]:443 ssl http2;
# Hostnamen für den Zugriff, sollte mit dem Zertifikat übereinstimmen
server_name cloud.example.com;
# der Pfad zu den Daten der Nextcloud
root /srv/docker/nextcloud/html/;
location ~ \.php(?:$|/) {
# notwendig, weil im Docker-Container der Pfad der Nextcloud-Daten anders liegt. Sonst würde das try_files in der Konfiguration eine 404 generieren!
fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
# das original würde dem PHP-FPM mitteilen, die Dateien unter dem root (siehe oben) zu suchen, deshalb passen wir den Pfad zu den PHP-Dateien an
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Weiterleitung von /push/ an den Container ausführender Push-Binary
# Nur nötig wenn auch Push installiert und gestartet wird (siehe compose)
location /push/ {
proxy_pass http://192.168.125.4:7867/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Wichtige Hinweise (Berechtigungen des Sockets)
Bei Verwendung des Unix-Sockets sollte geprüft werden, ob nginx auf diesen zugreifen darf. Das PHP-FPM im Container wird als Benutzer www-data (UID 33, GID 33) ausgeführt und wird den Socket für die selbe ID anlegen.
Wird nginx mit einer anderen ID ausgeführt (z.B. Archlinux), muss dies korrigiert werden. Unter Ubuntu läuft nginx unter der selben ID und funtioniert somit auf Anhieb.
Anpassung der PHP-Einstellungen
Hier findet man eine Anleitung für die Anpassung von Nextclouds PHP Einstellungen: https://dr3st.de/nextcloud-php-einstellungen-im-docker-setup/
Hier wird auch beschrieben, wie von TCP auf Unix-Socket umgestellt wird.
Dies ist nach Verwendung der obigen docker-compose.yml absolut notwendig, andernfalls startet der Container nicht, weil das config/php-fpm.d Verzeichnis leer ist!