8. Die Site ausliefern: Velocity, Apache, nginx und FrankenPHP
Ein installiertes Exponential ist ein Verzeichnis voller PHP-Dateien; irgendetwas muss Verbindungen annehmen, HTTP und
HTTPS sprechen, statische Dateien ausliefern und jede andere Anfrage an einen Front-Controller weiterreichen. Dieses
Kapitel zeigt, wie das geht. Es beginnt mit Exponential Velocity, dem Anwendungsserver, der für Exponential
ausgeliefert wird und in jeder Phase von der Entwicklung bis zur Produktion der empfohlene Weg ist: Mit der Engine
qbix von Velocity ist weder ein separater Webserver noch ein separater HTTPS-Server nötig. Velocity lauscht selbst
auf den HTTP- und HTTPS-Ports, hält die Anwendung in persistenten Workern geladen, beantwortet wiederholte Seitenabrufe
aus seinem eigenen Antwort-Cache und verwaltet seine eigenen Zertifikate, einschließlich eines selbstsignierten
Ersatzzertifikats und Let's Encrypt. Anschließend behandelt das Kapitel die klassischen Setups (Apache mit PHP-FPM,
auch unter Plesk; nginx; FrankenPHP), die Dateiberechtigungen, die jedes Setup braucht, und den Betrieb hinter einem
Reverse Proxy.
Warnung
.htaccessbremst jede Anfrage. Sind.htaccess-Dateien erlaubt (AllowOverridealles außerNone), geschweige denn genutzt, sucht Apache sie bei jeder Anfrage in jedem Verzeichnis des Pfads und liest und wertet sie aus, und die Ladezeiten der Seiten steigen drastisch (gemessen). Die einzige wirkliche Abhilfe ist, die Funktion für den virtuellen Host abzuschalten:AllowOverride Noneim virtuellen HTTPS-Host, und die Regeln in der Konfiguration des virtuellen Hosts selbst als mod_rewrite-Regeln. Das ist in Geschwindigkeitstests im Produktivbetrieb weit schneller und die Zeit für die Optimierung einer Produktivkonfiguration unbedingt wert. Stellen Sie sofort um: Übernehmen Sie die Regeln des Beispiels für einen virtuellen HTTPS-Host in Ihren virtuellen Host (mit dem statischen Cache auchstaticcache_offload.conf), setzen SieAllowOverride None, führen Sieapachectl configtestaus, laden Sie Apache neu und testen Sie die Website. Dieselben Regeln für andere Server: nginx, LiteSpeed, Caddy, IIS, Velocity (eingebaut); wohin Regeln für virtuelle Hosts in einem Control Panel gehören: Plesk, cPanel, DirectAdmin, ISPConfig. Unter LiteSpeed oder OpenLiteSpeed kann zusätzlich der Seiten-Cache des Servers anonyme Besucher und Crawler ohne PHP bedienen: Seiten-Caching mit LiteSpeed und OpenLiteSpeed.
Inhalt · Zurück: 7. Die Installation über die Konsole · Weiter: 9. Datenbanken
Inhalt dieses Kapitels
- Die Wahl in einer Tabelle
- Wie eine Anfrage beantwortet wird
- Exponential Velocity, der empfohlene Weg
- Das Engine-Paket installieren
- Die Engine wählen
- Einstellungen: wo sie liegen und wie man sie ändert
- Der erste Start
- Adresse, Ports, Benutzer und Gruppe
- Worker: Pool-Größe, der dynamische Pool und die Zygote
- Persistente Worker und KeepGlobals
- Der Antwort-Cache
- HTTPS direkt von Velocity
- Der Konfigurationsbaum: /etc/vc im Debian-Stil
- Velocity als Dienst betreiben
- Logs
- Das Dashboard und das Control Panel
- Eine Änderung bereitstellen: exp:velocity deploy
- Das Engine-Archiv: engine.phar
- Befehlsreferenz
- FrankenPHP
- Apache mit PHP-FPM
- nginx mit PHP-FPM
- Dateiberechtigungen und Eigentümer
- Hinter einem Reverse Proxy
- Checkliste
- Referenzen
Jeder Befehl in diesem Kapitel wird im Installationsverzeichnis ausgeführt, also in dem Verzeichnis, das index.php
enthält. Die Konsole ist bin/php/console; ./console ist dasselbe Programm, sofern die Installation die übliche
Abkürzung hat. Wenn Sie einen Befehl als root ausführen, fügen Sie --allow-root-user hinzu; ein Skript, das dies
benötigt, weist darauf hin.
8.1 Die Wahl in einer Tabelle
Exponential Velocity (qbix) | FrankenPHP (über Velocity) | Apache + PHP-FPM | nginx + PHP-FPM | |
|---|---|---|---|---|
| Rolle | empfohlen für jede Phase | produktionsreife Alternative | klassisch | klassisch |
| PHP-Version | 8.0 oder neuer (vom Engine-Paket vorausgesetzt, ab dem Release 0.0.4.54; bis dahin 8.1) | das in die Binärdatei eingebaute PHP (8.5 in den Releases 1.12) | 8.0 oder neuer | 8.0 oder neuer |
| Separater Webserver nötig | nein | nein (Caddy ist in die Binärdatei eingebaut) | ja | ja |
| Separates HTTPS-/Zertifikatswerkzeug nötig | nein: eigene Zertifikate, selbstsignierter Ersatz, ACME | nein: Ihr Zertifikat oder ein selbstsigniertes | ja (mod_ssl plus certbot oder ein Hosting-Panel) | ja |
| Herkunft des Codes | Composer-Paket se7enxweb/exponential-velocity | Binärdatei, von exp:velocity install heruntergeladen und per SHA-256 geprüft | das Betriebssystem | das Betriebssystem |
| Anwendung bleibt zwischen Anfragen im Speicher | ja (persistente Worker) | nein (sauberer Zustand je Anfrage) | nein | nein |
| Antwort-Cache vor PHP | ja | noch nicht | nein (nur die eigenen Caches des Kernels) | nein |
| HTTP/2 | ja | ja | mit mod_http2 | mit http2 |
| Rewrite-Regeln | eingebaut, dieselbe Liste wie .htaccess_root | generierte Caddyfile, dieselbe Liste | .htaccess_root | von Ihnen geschrieben (Abschnitt 8.6) |
| Befehle | exp:velocity start, stop, graceful, deploy, ... | dieselben Befehle | systemctl, apachectl | systemctl, nginx -t |
| Geeignet für Shared Hosting | meist nicht (braucht einen dauerhaft laufenden Prozess) | meist nicht | ja | selten |
Der eingebaute Server von PHP (php -S) ist eine dritte Velocity-Engine. Er ist nur deshalb die ausgelieferte
Voreinstellung, weil er keine zusätzliche Installation braucht; er ist für die Entwicklung gedacht, hat kein TLS und
ist nicht für Besucher bestimmt.
Verwenden Sie einen klassischen Server, wenn Ihr Hosting keine dauerhaft laufenden Prozesse erlaubt, wenn Sie bereits ein abgestimmtes Apache oder nginx betreiben, das Sie behalten möchten, oder wenn mehrere Kunden auf einem Rechner auf Betriebssystemebene voneinander isoliert sein müssen (betreiben Sie dann einen Velocity-Server je Website, jeden unter einem eigenen Benutzer, oder einen klassischen Server mit einem PHP-FPM-Pool je Website). Ein Rechner mit nur PHP 8.0 (dem Standard-PHP von Red Hat Enterprise Linux 9 und seinen Nachbauten) führt Velocity ebenfalls aus, ab dem Release 0.0.4.54 der Engine (siehe Kapitel 2).
Die Möglichkeiten schließen sich nicht gegenseitig aus. Eine verbreitete Form ist, dass Velocity die Website ausliefert und Apache oder nginx während einer Migration auf denselben Dateien bestehen bleibt; Abschnitt 8.7.2 erklärt, was das für die Eigentümer der Dateien bedeutet, und Abschnitt 8.3.14, wie ein einziges Deploy beide auf den neuesten Stand bringt.
8.2 Wie eine Anfrage beantwortet wird
Was auch immer die Website ausliefert: Das Document Root ist das Installationsverzeichnis, und es gilt dasselbe
Routing. Es ist einmal in .htaccess_root niedergeschrieben; die Engines von Velocity und die generierte
FrankenPHP-Konfiguration setzen dieselbe Liste Regel für Regel um (expVelocity::STATIC_PATHS, FRONT_CONTROLLERS
und ENTRY_SCRIPTS in kernel/classes/expvelocity.php).
request path
|
+---------------+-----------------------------------------------+
| |
a dot file or dot directory (.git, .env, .htaccess) -----------------> 404 (qbix: 403)
(.well-known stays reachable) |
| |
an existing .php/.phtml/.phar below the root ------------------------> 404
| |
/api/... ------------------------------------------------------------> index_rest.php
/content/treemenu..., /<siteaccess>/content/treemenu... -------------> index_treemenu.php
| |
a listed asset path (design and extension stylesheets, images, |
scripts and fonts; var/*/storage/images; image originals; |
stored PDF exports; public caches; share/icons; extension/<name>/icons |
(images with one extension only); package previews; |
favicon.ico, robots.txt, index.js, sw.js, w3c/p3p.xml) --------------> sent as a file
| |
everything else (URL aliases, modules, /settings/site.ini, ...) -----> index.phpZwei Folgen sind für die Sicherheit wichtig und werden in Kapitel 13 noch einmal behandelt:
- Keine PHP-Datei wird ausgeführt, nur weil ihr Pfad angefragt wurde, mit Ausnahme der Front-Controller im Wurzelverzeichnis.
- Eine Datei außerhalb der Liste wird nie ausgeliefert.
settings/site.ini, die SQLite-Datenbank oder eine Kernel-Quelldatei, die per Pfad angefragt wird, landen beiindex.php(das mit einer Seite oder einem 404 antwortet), nie die Datei selbst. Hochgeladene Originale, die keine Bilder sind, werden nur übercontent/downloadausgeliefert, das die Berechtigungen prüft. - Selbst innerhalb eines gelisteten Asset-Verzeichnisses wird ein Skript (
.php,.phtml,.phar) oder ein Punkt-Pfad nie als Datei gesendet (expVelocity::NEVER_STATIC; die zweite Regel von.htaccess_root), sodass ein verirrtes Skript im Design-Verzeichnis einer Extension weder ausgeführt werden noch seinen Quelltext preisgeben kann.
Prüfen Sie es auf jedem Server. Sobald die Website antwortet, zeigen diese vier Anfragen, dass das Routing aktiv ist. Ersetzen Sie die Adresse durch Ihre eigene:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8088/.git/config # 404 (403 from the qbix engine)
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8088/kernel/classes/ezcontentobject.php # 404
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8088/robots.txt # 200 when the file exists
curl -s http://127.0.0.1:8088/settings/site.ini | grep -c '^\[DatabaseSettings\]' # 0: a page, not the fileWas schiefgehen kann: Ein 200 für die .git- oder die Kernel-Anfrage bedeutet, dass die Regeln nicht aktiv sind
(Apache ohne .htaccess oder AllowOverride, ein nginx-Block, der nicht der aus diesem Kapitel ist); halten Sie an
und beheben Sie das, bevor die Website von außen erreichbar ist. Ein 404 für jedes Asset unter design/ bedeutet,
dass das Document Root nicht das Installationsverzeichnis ist.
WebDAV steht nicht in dieser Liste. Es ist standardmäßig aus, und die mitgelieferten Regeln schicken
/index_webdav.php wie jedes andere Skript an index.php. Um WebDAV auszuliefern, kommentieren Sie
RewriteRule ^index_webdav\.php - [L] in .htaccess ein (oder schreiben dieselbe Regel in den HTTPS-Host), oder Sie
geben WebDAV einen eigenen Host, der jede Anfrage an index_webdav.php schickt. Velocity und die
FrankenPHP-Konfiguration liefern WebDAV nicht aus; verwenden Sie dafür Apache oder nginx mit PHP-FPM. Seit 6.0.15
heißt das Skript index_webdav.php, nicht webdav.php: Regeln für den alten Namen funktionieren über einen
weiterleitenden Shim weiter, der in einer späteren Hauptversion entfernt wird. Die Regeln für jeden Server und der Test
(curl -X PROPFIND -H 'Depth: 1', erwartet: 207 Multi-Status) stehen in
Das WebDAV-Einstiegsskript heißt jetzt index_webdav.php.
Auch SOAP steht nicht in dieser Liste. Es ist standardmäßig aus (soap.ini EnableSOAP=false). Um es
auszuliefern, kommentieren Sie RewriteRule ^index_soap\.php - [L] in .htaccess ein (oder schreiben dieselbe Regel
in den HTTPS-Host). Velocity und die FrankenPHP-Konfiguration liefern SOAP nicht aus; verwenden Sie dafür Apache oder
nginx mit PHP-FPM. Seit 6.0.15 heißt das Skript index_soap.php, nicht soap.php: Regeln und Clients mit dem
alten Namen funktionieren über einen weiterleitenden Shim weiter, der in einer späteren Hauptversion entfernt wird.
Testen Sie es nach dem Neuladen: curl -sS -i 'https://www.example.com/index_soap.php?wsdl' antwortet mit 200 und
Error: this web page does only understand POST methods; ein 404 oder eine Seite der Website bedeutet, dass die
Regel fehlt. Die Regeln für jeden Server und der vollständige Test stehen in
Das SOAP-Einstiegsskript heißt jetzt index_soap.php.
8.3 Exponential Velocity, der empfohlene Weg
Velocity ist seit 6.0.15 Teil von Exponential. Die composer.json im Wurzelverzeichnis verlangt
se7enxweb/exponential-velocity ~0.0.4.57, also hat das composer install aus
Kapitel 3 es schon installiert, auf demselben PHP wie den Kernel
(8.0 und höher, das mitgelieferte PHP 8.0 von Red Hat Enterprise Linux 9 eingeschlossen). Vor dem ersten
exp:velocity start ist nichts zusätzlich herunterzuladen. Das ist der Wendepunkt der Linie 6.0: Der Internet / Web
Application Server ist ein Grundstein des Kernprodukts, sodass Ausliefern, Cachen, HTTPS und Deployment ab Werk und
standardmäßig aus derselben Quelle kommen wie die Anwendung. Der Hintergrund:
Velocity ist Teil von Exponential 6.0.15.
Die vier Befehle der täglichen Arbeit:
./console exp:velocity deploy --allow-root-user # after a change: autoloads, settings, caches, PHP-FPM, Velocity
./console exp:velocity start --allow-root-user
./console exp:velocity restart --allow-root-user # workers load changed classes and settings
./console exp:velocity cache clear --allow-root-user # empty the response cacheVelocity ist ein Anwendungsserver, der für Exponential geschrieben wurde. Ein Elternprozess lädt die Anwendung einmal und forkt Worker, die eine Anfrage nach der anderen beantworten; zwischen den Anfragen wird jeder Worker in den Zustand zurückversetzt, den er beim Forken hatte. Der Elternprozess nimmt jede Verbindung selbst an, beantwortet statische Dateien, Treffer im Antwort-Cache und seine eigenen Seiten, ohne einen Worker einzubeziehen, und terminiert TLS. Deshalb braucht eine Velocity-Website weder Apache noch nginx, PHP-FPM oder einen separaten TLS-Terminator.
Internet
|
:80 / :443 (or 8088 / 8080 as shipped)
|
+-------------------v--------------------------------------------+
| Velocity parent process (root when started as root) |
| - binds the ports, reads the certificate, speaks TLS, HTTP/2 |
| - static files, response-cache hits, /Q/ pages |
| - hands PHP requests to an idle worker |
+--------+-------------------+-------------------+---------------+
| | |
worker (site user) worker (site user) ... (forked by the zygote)
Exponential kept loaded, reset after each requestDer Befehl exp:velocity (auch als exp:vc oder direkt als php bin/php/velocity.php erreichbar) steuert drei
Engines mit denselben Verben: qbix (der eigene Server von Velocity, Thema dieses Abschnitts), frankenphp
(Abschnitt 8.4) und php (der eingebaute Entwicklungsserver von PHP).
8.3.1 Das Engine-Paket installieren
Die composer.json von Exponential verlangt die Engine als ~0.0.4.57, sodass composer install sie unter jedem
unterstützten PHP installiert, 8.0 eingeschlossen. Bis zu ihrem Release 0.0.4.54 brauchte die Engine PHP 8.1 und wurde
nur vorgeschlagen; eine Installation aus dieser Zeit fügt sie mit Composer hinzu:
composer require se7enxweb/exponential-velocity:~0.0.4.57Sie landet in vendor/se7enxweb/exponential-velocity (der frühere Paketname se7enxweb/qbix-webserver wird weiterhin
gefunden). Die Tilde-Einschränkung folgt der letzten Versionsstelle der Engine, sodass ~0.0.4.57 spätere
0.0.4.x-Releases akzeptiert.
Die composer.json des Pakets setzt PHP 8.0 ("php": ">=8.0", ab dem Release 0.0.4.54; zuvor >=8.1) und die
Extension sockets voraus (TCP-Optionen für Client-Verbindungen und die Zygote aus Abschnitt 8.3.6), daher lehnt
Composer das Paket ohne sockets ab. Unter PHP 8.0 unterscheiden sich einige Dinge (die Ausgabe als AVIF, die Spalte
mit der Speicherspitze im Dashboard, full_path in $_FILES);
Kapitel 2 führt sie auf. Die Engine möchte außerdem pcntl und posix, um Worker zu forken und deren Benutzer zu wechseln,
sowie openssl für HTTPS. Beim Start verweigert sie den Betrieb ohne Prozessisolation (pcntl oder eine
php-cgi-Binärdatei) und, wenn HTTPS konfiguriert ist, ohne openssl, und gibt dabei den Installationsbefehl aus; für
den Rest ihres Standardumfangs warnt sie einmal und startet. Um zu sehen, was diesem PHP fehlt, zusammen mit dem
Befehl, der es auf diesem Betriebssystem installiert:
php bin/php/console exp:velocity ext check
php bin/php/console exp:velocity ext install-hint <extension>Beides sind die engine-eigenen Befehle qbixctl ext:check und ext:install-hint, ausgeführt mit der Konfiguration
dieser Installation; ext check ohne Argumente ist die Standardaktion.
Das Engine-Paket gibt es auch als Betriebssystempaket (exponential-velocity, deb und rpm, mit einer systemd-Unit) und
als Docker-Image; siehe Velocity-Pakete, Docker-Images und Binärdateien.
Für eine Exponential-Installation ist das Composer-Paket dasjenige, das exp:velocity steuert.
8.3.2 Die Engine wählen
settings/velocity.ini wird mit [ServerSettings] Engine=php ausgeliefert, weil der eingebaute Server von PHP immer
funktioniert. Für jede echte Website setzen Sie qbix:
php bin/php/console exp:velocity config set --apply ServerSettings Engine qbix| Engine | Rolle | Ausgelieferte Ports (HTTP / HTTPS) | Hinweise |
|---|---|---|---|
qbix | empfohlen: von der Entwicklung bis zur Produktion | 8088 / 8080 ([ServerSettings] Port, HTTPSPort) | persistente Worker, Antwort-Cache, TLS, HTTP/2, Baum /etc/vc |
frankenphp | produktionsreife Alternative | 8089 / 8444 ([FrankenPHPSettings]) | eine heruntergeladene Binärdatei; sauberer Zustand je Anfrage; HTTPS standardmäßig an |
php | Entwicklung (ausgelieferte Voreinstellung) | 8087 / keiner ([PHPServerSettings]) | php -S mit bin/php/velocity-router.php; kein TLS, kein Reload |
Engine ist nur die Voreinstellung: --engine=<name> spricht für einen Befehl eine andere Engine an,
--engine=php,qbix mehrere, --all jede Engine (für start, stop, restart, graceful, kill und status).
Jede Engine hat ihren eigenen Port, ihre eigene PID-Datei und ihre eigenen Logs, sodass sie für Tests nebeneinander
laufen können. Eine Website wird von einer einzigen ausgeliefert.
8.3.3 Einstellungen: wo sie liegen und wie man sie ändert
| Datei | Was sie ist |
|---|---|
settings/velocity.ini | die ausgelieferten Voreinstellungen, jede Einstellung kommentiert; bearbeiten Sie sie nie |
settings/override/velocity.ini.append.php | die Werte dieser Installation; geschrieben von exp:velocity config set |
/etc/vc/... (oder var/vc/qbix/etc/ ohne root) | der Konfigurationsbaum der Engine, bei jedem Start aus den beiden obigen Dateien erzeugt (Abschnitt 8.3.10) |
php bin/php/console exp:velocity config list # every setting; * marks the ones you set
php bin/php/console exp:velocity config list HTTPSSettings # one block
php bin/php/console exp:velocity config get ServerSettings Workers
php bin/php/console exp:velocity config set --apply ServerSettings Workers 16
php bin/php/console exp:velocity config unset --apply ServerSettings Workers # back to the shipped value
php bin/php/console exp:velocity config paths # which file is whichEine geänderte Einstellung erreicht den Server beim nächsten restart (oder graceful). Die Worker halten die
Anwendung im Speicher, daher gilt dasselbe für eine geänderte Klasse oder INI-Datei der Anwendung selbst
(Abschnitt 8.3.14).
8.3.4 Der erste Start
php bin/php/console exp:velocity start
php bin/php/console exp:velocity statusstart schreibt die Konfiguration, startet den Server im Hintergrund (mit setsid abgekoppelt), wartet, bis der Port
antwortet, und gibt dann den Status aus. status listet jede Adresse, die sich öffnen lässt, als vollständige URL auf:
jede Website, die über einen Pfad erreicht wird, die Anmeldung zur Administration, Setup > Systeminformationen und
Setup > Caches, neben jeder einfachen Adresse die HTTPS-Adresse, wenn HTTPS aktiv ist, sowie das eigene Dashboard des
Servers. Darunter zeigt er den Prozess, die Version, die Konfiguration, den HTTPS-Zustand, die Log-Pfade und jede
Einstellung, auf die die laufende Engine nicht reagiert.
Mit den ausgelieferten Werten antwortet die Website unter http://127.0.0.1:8088/ und ist nur vom Rechner selbst aus
(oder über einen SSH-Tunnel) erreichbar. Prüfen Sie es:
curl -sI http://127.0.0.1:8088/ | head -1Erwarten Sie HTTP/1.1 200 OK oder eine Weiterleitung. status --json liefert dieselben Informationen für das
Monitoring.
Was beim ersten Start schiefgehen kann:
| Sie sehen | Warum | Was zu tun ist |
|---|---|---|
velocity: no server script at ... | das Engine-Paket ist nicht installiert | Abschnitt 8.3.1, oder --engine=php für einen schnellen Blick |
velocity: port ... is already in use by another process (die Engines php und frankenphp), oder ein qbix-Start, der nicht hochkommt, mit dem Bind-Fehler in console.log | eine andere Engine oder ein anderes Programm belegt den Port | exp:velocity status --all; die andere beenden oder Port ändern |
der Start gelingt, aber curl von einem anderen Rechner bekommt keine Antwort | Host ist noch 127.0.0.1 | Abschnitt 8.3.5 |
| eine Warnung, dass die Worker als root laufen | nichts benennt einen Worker-Benutzer, und das Document Root gehört root | Abschnitt 8.3.5, dann 8.7 |
| eine Seite, die meldet, dass sich die Website in Wartung befindet | ein Installationslauf hat den Wartungsmodus eingeschaltet gelassen | php bin/php/maintenance.php status, dann off |
Die Startzeilen, einschließlich des Worker-Benutzers (Workers as: ...) und des TLS-Zustands, stehen in
var/vc/qbix/run/console.log (Abschnitt 8.3.12).
8.3.5 Adresse, Ports, Benutzer und Gruppe
Um Besucher direkt zu bedienen, binden Sie an alle Adressen auf den Standardports:
php bin/php/console exp:velocity config set --apply ServerSettings Host 0.0.0.0 --allow-root-user
php bin/php/console exp:velocity config set --apply ServerSettings Port 80 --allow-root-user
php bin/php/console exp:velocity config set --apply ServerSettings HTTPSPort 443 --allow-root-user
php bin/php/console exp:velocity restart --allow-root-userEinstellung ([ServerSettings]) | Ausgeliefert | Bedeutung |
|---|---|---|
Host | 127.0.0.1 | Bind-Adresse. Die Voreinstellung hält den Server nur lokal, über einen Tunnel oder einen Reverse Proxy erreichbar |
Port | 8088 | einfaches HTTP |
HTTPSPort | 8080 | HTTPS, verwendet, wenn HTTPS aktiv ist (Abschnitt 8.3.9) |
DocumentRoot | leer | leer bedeutet das Installationsverzeichnis, was richtig ist |
User, Group | leer | unter wem die Worker laufen, wenn der Server als root gestartet wird |
AllowRootWorkers | disabled | root als Worker-Benutzer wird abgelehnt, außer bei enabled |
FollowSymlinks | disabled | eine Datei, die über einen symbolischen Link aus dem Document Root hinausführt, wird abgelehnt (403 bei qbix) |
HTTP2 | enabled | HTTP/2 für Clients, die es beim TLS-Handshake aushandeln |
StaticMaxAge | 31536000 | Lebensdauer von Stylesheets, Skripten und Bildern im Browser-Cache, in Sekunden. Eine unter demselben Namen ersetzte Datei wird erst nach Ablauf erneut abgerufen; setzen Sie den Wert herab, während Sie an einem Stylesheet arbeiten |
ResponseHeaders[] | X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy | Header, die jeder Antwort hinzugefügt werden, die der Server selbst erzeugt (statische Dateien, skalierte Bilder, seine eigenen Fehlerseiten, Weiterleitungen); ein bereits vorhandener Header wird nie ersetzt. Strict-Transport-Security hat eine eigene Einstellung (Abschnitt 8.3.9) |
ResponseHeadersOnScripts | enabled | dieselben Header auch dem hinzufügen, was index.php, index_rest.php und index_treemenu.php antworten, sofern das Skript diesen Header nicht selbst gesendet hat |
Ports unter 1024 brauchen root. Als root gestartet, behält der Elternprozess root (er bindet die Ports, liest das Zertifikat und führt Reloads aus), und jeder Worker gibt root unmittelbar nach dem Forken ab, bevor irgendein Anwendungscode läuft. Unter welchem Benutzer die Worker laufen, wird in dieser Reihenfolge entschieden, der erste Treffer gewinnt:
[ServerSettings] UserundGroupinvelocity.ini(übergeben als--userund--group);VC_RUN_USERundVC_RUN_GROUPaus der Umgebung oder Zeilenexport VC_RUN_USER=...in/etc/vc/envvars(die Engine liest auchQBIX_RUN_USERundQBIX_RUN_GROUP);- der Eigentümer und die Gruppe des Document Root.
Ein Benutzer oder eine Gruppe, die nicht existiert, bricht den Start ab. Ist nichts konfiguriert und gehört das
Document Root root, bleiben die Worker root, und der Start weist darauf hin: Geben Sie der Installation einen eigenen
Benutzer (Abschnitt 8.7) oder setzen Sie User und Group. Setzen Sie sie auf den Benutzer, dem die Dateien gehören:
php bin/php/console exp:velocity config set --apply ServerSettings User example --allow-root-user
php bin/php/console exp:velocity config set --apply ServerSettings Group example --allow-root-userAls gewöhnlicher Benutzer gestartet, läuft der Server vollständig unter diesem Benutzer; verwenden Sie dann Ports über 1024 und stellen Sie einen Reverse Proxy oder eine Firewall-Weiterleitung davor (Abschnitt 8.8).
8.3.6 Worker: Pool-Größe, der dynamische Pool und die Zygote
Einstellung ([ServerSettings]) | Ausgeliefert | Bedeutung |
|---|---|---|
Workers | 4 | die Größe des Pools; ist SpareWorkers gesetzt, die Höchstzahl, auf die er wächst. Setzen Sie sie immer ausdrücklich |
SpareWorkers | 0 | 0: fester Pool. Über 0: ein dynamischer Pool, der so viele Worker untätig bereithält, weitere forkt, wenn alle beschäftigt sind (bis zu Workers), und überzählige wieder beendet |
IdleWorkerTimeout | 60 | Sekunden, die ein zusätzlicher Worker untätig bleiben darf, bevor er beendet wird |
Instances | 1 | Anzahl der Server, die sich mit SO_REUSEPORT dieselben Ports teilen (Linux und die BSDs); Workers und SpareWorkers gelten je Instanz |
Zygote | leer (Voreinstellung der Engine: an) | neue Worker aus einem Prozess forken, der nie eine Client-Verbindung gehalten hat |
StatTtl | 0 | Sekunden, die ein Worker Dateiinformationen (Existenz, mtime, Größe) über Anfragen hinweg behalten darf; höchstens 10 |
Dimensionierung. Ein Worker eines vollständigen Exponential kostet etwa 10 bis 11 MB eigenen Speicher (gemessen als
PSS auf 12 Kernen und PHP 8.5); der gemeinsam genutzte Teil, etwa 47 MB, fällt nur einmal an. Beurteilen Sie den
Speicher nach PSS oder privatem Speicher, nie nach RSS, das jede gemeinsam genutzte Seite einmal je Worker zählt und
einen Pool um ein Vielfaches zu groß ausweist. Sind alle Worker beschäftigt, wartet eine Anfrage im Elternprozess; sie
wird erst abgewiesen, wenn das Verbindungslimit (maxConnections, 1024) erreicht ist.
Ein guter Ausgangspunkt für eine Produktions-Website ist ein dynamischer Pool:
# settings/override/velocity.ini.append.php
[ServerSettings]
Workers=64
SpareWorkers=8
IdleWorkerTimeout=60Instanzen. Ein Server beantwortet gecachte Seiten in seinem eigenen Prozess und ist auf einen Kern begrenzt (gemessen: etwa 2.950 gecachte Seiten pro Sekunde über TLS; vier Instanzen, etwa 12.000). Gerenderte Seiten sind durch die Worker begrenzt, nicht durch die Anzahl der Instanzen.
Die Zygote. fork() übergibt einem neuen Worker jeden Deskriptor, den der Server hält, einschließlich offener
Besucherverbindungen. Ein Worker, der unter Last vom Server geforkt wurde, hielt deshalb Verbindungen offen, bis er
beendet wurde. Die Zygote ist ein Prozess, der geforkt wird, bevor die erste Verbindung angenommen wird; spätere Worker
werden von ihr geforkt und erben keine Verbindungen. Sie braucht die Extension sockets; schlägt sie fehl, werden die
Worker wie bisher vom Server geforkt, und das Log meldet dies.
Worker werden außerdem von selbst ersetzt: nach maxRequests Anfragen (1000), wenn der Heap workerMemoryCeiling
überschreitet oder wenn eine Anfrage länger als requestTimeout läuft (30 Sekunden; der Client erhält 504). Dies sind
Engine-Einstellungen unter Q.webserver, beschrieben in der Spezifikation des Worker-Pools.
8.3.7 Persistente Worker und KeepGlobals
[ServerSettings] ForkPerRequest entscheidet, wie lange ein Worker lebt:
| Wert | Verhalten |
|---|---|
disabled (ausgeliefert) | persistente Worker: Jeder bedient viele Anfragen; der Zustand der Anfrage wird geleert, nachdem die Antwort hinausgegangen ist |
enabled | eine Anfrage je Worker, dann ein frischer Fork: die Isolation von PHP-FPM, um den Preis, dass jede Anfrage kalt startet |
Persistente Worker behalten Datenbankverbindungen, Stat-Caches und alles, was der Kernel je Prozess vorhält. Gemessen
an einer Seite der Administration mit angemeldetem Benutzer: 256 bis 284 ms mit einem frischen Worker je Anfrage, 73
bis 80 ms mit persistenten Workern. Sie brauchen eine Engine, die REQUEST_TIME_FLOAT je Anfrage setzt und in diesem
Modus Header und Shutdown-Funktionen mitführt (Header und Shutdown-Funktionen ab qbix-webserver 0.0.4.25, das
REQUEST_TIME_FLOAT je Anfrage ab Exponential Velocity 0.0.4.42; Exponential verlangt 0.0.4.54).
Zwischen den Anfragen setzt der Worker statische Klasseneigenschaften, Superglobals, eigene Globals, Ausgabepuffer,
Handler und Antwort-Header auf den Zustand zurück, mit dem er geforkt wurde. Einige Registries im Kernel werden mit
include_once gefüllt und könnten nach dem Leeren nie wieder gefüllt werden; sie müssen daher behalten werden: die
Registries für Datentypen, Workflow-Ereignisse, Benachrichtigungsereignisse und Payment-Gateways. Auch der
Worker-Bereich des Kernel-Service-Containers (expKernelServicesWorker) wird behalten: Er hält die Einstellungsdateien
jedes Siteaccess, einmal pro Worker statt bei jeder Anfrage gebaut
(der Kernel-Service-Container). Diese Namen sind
eingebaut (expVelocity::DEFAULT_KEEP_GLOBALS) und brauchen keine Einstellung.
[ApplicationSettings]
# Adds to the built-in list. Only for a global filled once by include_once.
KeepGlobals[]
KeepGlobals[]=MyExtensionRegistry
# disabled starts from an empty list (for a kernel without those registries)
KeepGlobalsDefaults=enabled--keep-global=Name[,Name] fügt Namen für ein einzelnes start, restart oder command hinzu; exp:velocity command
gibt die vollständige Befehlszeile aus, exp:velocity layout die resultierende Liste. Behalten Sie nichts anderes:
Ein anfragebezogenes Global, das zwischen Anfragen behalten wird, lässt die Anfrage eines Besuchers in die nächste
durchsickern.
[ServerSettings] PreloadWarmup (eine Seite im Elternprozess vor dem Forken rendern) wird deaktiviert ausgeliefert
und sollte es bleiben; die Einstellungsdatei erklärt, welche Funktionen dadurch kaputtgingen.
8.3.8 Der Antwort-Cache
Der Antwort-Cache hält gerenderte anonyme Seiten vor und beantwortet wiederholte Anfragen im Serverprozess, bevor ein
Worker gewählt wird: kein Fork, kein PHP, keine Datenbank. Exponential konfiguriert ihn in [CacheSettings]:
| Einstellung | Ausgeliefert | Bedeutung |
|---|---|---|
Enabled | enabled | der Cache ist an (er braucht qbix-webserver 0.0.4.26 oder neuer, das das Sitzungs-Cookie erkennt) |
DefaultTtl | 30 | Sekunden, die eine anonyme Seite vorgehalten wird, wenn sie keine eigene Lebensdauer mitbringt |
Dir | var/cache/qbix-reverse | Plattenebene für Einträge, die für den Shared Memory zu groß sind |
APCu, APCuMaxSize | enabled, 0 | kleine Einträge in APCu, von den Workern gemeinsam genutzt (apc.enable_cli ist für den Serverprozess gesetzt) |
SkipCookies | leer | Cookies, die „persönlich, nicht cachen“ bedeuten; leer leitet das Sitzungs-Cookie und is_logged_in ab |
StaleWhileRevalidate | 60 | Sekunden, in denen eine abgelaufene Seite noch ausgeliefert wird, während eine Anfrage ihren Ersatz rendert |
NotFoundSeconds | 0 | Sekunden, die ein 404 gemerkt wird; 0 schickt jedes 404 an PHP, sodass 404.log und security.log jedes einzelne sehen |
HonorRequestNoCache | enabled | eine Anfrage mit Cache-Control: no-cache oder Pragma: no-cache erreicht PHP, und ihre Antwort wird neu gespeichert |
SweepEvery, SweepMaxAge | 300, 86400 | Entfernen abgelaufener Einträge von der Platte |
MinifyHtml | enabled | gespeicherte Seiten ohne Template-Einrückung |
Angemeldete Besucher werden nie aus dem Cache bedient, und eine Seite mit einem Formular-Token wird als private
gesendet. Nach einer Änderung an einem Template oder Stylesheet:
php bin/php/console exp:velocity cache clear --apply # every cached page is rendered again on its next request
php bin/php/console exp:velocity cache stats # where it is, how much it holds, when it was clearedPrüfen Sie einen Treffer mit zwei Anfragen: Die zweite trägt X-Cache: HIT und einen Age-Header.
Die eigenen Caches des Kernels (View-Cache für Inhalte, Template-Blöcke, der rollenbewusste HTTP-Cache in
settings/httpcache.ini, der SQL-Abfrage-Cache in settings/querycache.ini) funktionieren unter jedem Server; sie
werden mit bin/php/ezcache.php oder exp:cache geleert. Siehe die Seite zum Antwort-Cache.
8.3.9 HTTPS direkt von Velocity
Velocity terminiert TLS in seinem eigenen Prozess, mit HTTP/2. Mehr ist nicht nötig: kein mod_ssl, kein stunnel,
kein Reverse Proxy und für ein öffentliches Zertifikat nicht einmal certbot.
Die Engine setzt $_SERVER['HTTPS'] und REQUEST_SCHEME für die Anwendung. Eine Anfrage am TLS-Listener ist HTTPS,
gleich wer sie gesendet hat. Seit Velocity 0.0.4.44 ist auch eine Anfrage am einfachen Listener HTTPS, wenn sie von
einem vertrauenswürdigen Proxy kommt (Q.webserver.proxy.trusted, standardmäßig nur Loopback), der
X-Forwarded-Proto: https, CloudFront-Forwarded-Proto: https oder CF-Visitor: {"scheme":"https"} sendet; von jedem
anderen Client werden diese Header ignoriert. Siehe Abschnitt 8.8.
Mit einem vorhandenen Zertifikat
Jedes PEM-Zertifikat von einer CA oder einem Hosting-Panel (Endzertifikat mit Kette und dem privaten Schlüssel; eine Datei darf beides enthalten):
php bin/php/console exp:velocity config set --apply HTTPSSettings Certificate /etc/ssl/example.com/fullchain.pem --allow-root-user
php bin/php/console exp:velocity config set --apply HTTPSSettings Key /etc/ssl/example.com/privkey.pem --allow-root-user
php bin/php/console exp:velocity config set --apply HTTPSSettings Enabled true --allow-root-user
php bin/php/console exp:velocity restart --allow-root-user
php bin/php/console exp:velocity ssl show --allow-root-user
curl -sI https://example.com/ | head -1 # expect HTTP/2 200 or a redirectWas velocity.ini mit diesen Einstellungen macht (expVelocity::httpsEnabled() und writeServerConfig()):
- HTTPS wird nur eingeschaltet, wenn
Enabledauftrue(oderenabled) steht und beide Dateien existieren. Ein Pfad, der nicht existiert, lässt den Server bei einfachem HTTP, statt einen TLS-Port zu starten, der nicht funktionieren kann;statusmeldet, dass HTTPS aus ist und was es einschaltet. Relative Pfade werden vom Installationsverzeichnis aus gelesen. - Die Site-Datei enthält dann
Q.web.httpsmitmode: manualund den beiden Pfaden, und der Server wird mit--https-port=<HTTPSPort>gestartet. - Vor der Verwendung wird das Paar geprüft: Das Zertifikat lässt sich parsen, ist nicht abgelaufen, und der Schlüssel
gehört dazu. Ein Paar, das die Prüfung nicht besteht, wird nie einem Besucher gezeigt; ein selbstsigniertes
Zertifikat springt ein, bis das echte wieder verwendbar ist (der
fallbackder Engine, Voreinstellungself-signed;nonewürde HTTPS stattdessen abschalten). - Der Server liest eine private Kopie des Paars (
active-<port>-<fingerprint>-<pid>.pem), sodass eine Datei, die anderswo neu geschrieben wird, keinen Handshake stören kann. AllewatchIntervalSekunden (60) werden die Quelldateien geprüft, und ein geändertes, gültiges Paar wird im laufenden Betrieb eingewechselt, für die nächste Verbindung, ohne Neustart und ohne abgebrochene Verbindung. Eine Erneuerung durch Ihr eigenes Werkzeug wird daher innerhalb einer Minute übernommen. - HTTPS kommt vor einfachem HTTP hoch, sodass es nie einen Moment gibt, in dem der Server HTTP beantwortet, HTTPS aber nicht.
Der Serverprozess liest den Schlüssel als root, wenn er als root gestartet wurde, daher kann der Schlüssel bei
0600 root bleiben.
Auf den ausgelieferten Ports lautet die HTTPS-Adresse https://<host>:8080/, und einfaches HTTP bleibt auf 8088;
beide lauschen gleichzeitig, und velocity.ini hat keine Einstellung, die von einem auf das andere weiterleitet.
Stellen Sie sicher, dass die Adressen, die die Website erzeugt, die HTTPS-Adressen sind (site.ini [SiteSettings] SiteURL und die URLs der Siteaccesses), bevor Sie HSTSMaxAge erhöhen.
Strict-Transport-Security
[HTTPSSettings]
HSTSMaxAge=300 # seconds; 0 sends no header
HSTSIncludeSubDomains=disabled
HSTSPreload=disabledDer Header wird bei jeder HTTPS-Antwort gesendet (statische Dateien, die eigenen Seiten des Servers und die Antworten
der Skripte) und nie über einfaches HTTP. Ein Browser, der ihn gesehen hat, verweigert für diesen Host über den
gesamten Zeitraum einfaches HTTP, selbst nachdem Sie den Wert gesenkt haben. Erhöhen Sie ihn erst dann auf ein Jahr
(31536000), wenn jeder Name der Website dauerhaft über HTTPS ausgeliefert wird; Preload braucht
HSTSIncludeSubDomains und mindestens ein Jahr.
Let's Encrypt und andere ACME-CAs, Archive, PKCS#12
Das Zertifikats-Subsystem der Engine kann mehr, als velocity.ini zugänglich macht: Zertifikate von Let's Encrypt
oder jeder ACME-CA (ZeroSSL, Google) beziehen und erneuern, ein Zertifikat aus einem Archiv (.zip, .tar.gz, .7z
und andere) oder einem .p12/.pfx-Bündel lesen, übernehmen, was certbot bereits verwaltet, eines von einer URL
herunterladen oder ohne jede Datei ein selbstsigniertes Zertifikat erzeugen (die Modi letsencrypt, archive,
pkcs12, certbot, remote und self-signed neben manual). Diese Quellen werden unter Q.web.https in der
Konfiguration der Engine eingerichtet. Im Baum /etc/vc (Abschnitt 8.3.10) gehört alles in conf-available/ dem
Administrator und wird vor der generierten Site-Datei zusammengeführt, daher ist ein Snippet dort der richtige Ort
dafür. Lassen Sie [HTTPSSettings] Enabled in diesem Fall auf false, damit die generierten Dateien Q.web.https
nicht selbst setzen.
Voraussetzungen für die HTTP-01-Challenge: Das DNS jedes Namens zeigt auf diesen Rechner, und Port 80 dieses Servers
ist aus dem Internet erreichbar ([ServerSettings] Port 80), weil die CA dort
/.well-known/acme-challenge/... abruft.
cat > /etc/vc/conf-available/https-acme.conf <<'EOF'
{ "Q": { "web": { "https": {
"port": 443,
"mode": "letsencrypt",
"acme": {
"email": "[email protected]",
"domains": ["example.com", "www.example.com"],
"directory": "letsencrypt-staging"
}
} } } }
EOF
php bin/php/console exp:velocity conf enable --apply https-acme --allow-root-user
php bin/php/console exp:velocity restart --allow-root-user
php bin/php/console exp:velocity ssl show --allow-root-userAnmerkungen:
- Die Dateien des Baums sind JSON-Objekte unter den Dateinamen von Apache.
/etc/vcist der Baum, wennexp:velocityals root läuft; andernfalls nenntexp:velocity layoutdas verwendete Verzeichnis. - Zuerst
directory: letsencrypt-staging: Dessen Zertifikate werden von Browsern nicht als vertrauenswürdig anerkannt, aber seine Ratenlimits sind großzügig. Wennssl showein Staging-Zertifikat aufführt, entfernen Sie diese Zeile (die Voreinstellung istletsencrypt) und starten Sie neu. - Bis das erste Zertifikat eintrifft, wird das selbstsignierte ausgeliefert; das CA-Zertifikat ersetzt es im laufenden Betrieb.
- Die Erneuerung läuft im Hintergrund, wenn noch ein Drittel der Laufzeit übrig ist (
renewAt0.33), mit wachsenden Pausen nach einem Fehlschlag (5 Minuten, verdoppelt bis zu einem Tag), sodass Ratenlimits nie aufgebraucht werden.exp:velocity ssl renew [host...]fordert sie sofort an. keyType(standardmäßigec256),challenge: dns-01mit einemdnsHook-Programm (für Wildcards nötig),webroot(wenn ein anderer Server Port 80 belegt),eab(External Account Binding) und die übrigen Schlüssel sind in Velocity: HTTPS und Zertifikate und in derdocs/https.mdder Engine aufgeführt.startmeldet, dass sich die Konfiguration wegen des aktivierten Snippets vonvelocity.iniunterscheidet; das ist zu erwarten.- Sichern Sie das Verzeichnis
ssl/des Konfigurationsverzeichnisses, mit dem der Server läuft (dasQ.webserver.confDirder Engine, sofernselfSigned.dirkein anderes nennt). Alles darin lässt sich neu erzeugen, außer den ACME-Kontoschlüsseln (acme/account-<ca>.pem).
Für ein Zertifikat in einem Archiv oder Bündel verwenden Sie "mode": "archive" mit "archive": "<file>" oder
"mode": "pkcs12" mit "bundle": "<file>" und einem password, passwordFile oder passwordEnv. Für die
Entwicklung ganz ohne Zertifikat:
{ "Q": { "web": { "https": { "port": 8443, "mode": "self-signed" } } } }.
Zertifikate untersuchen
php bin/php/console exp:velocity ssl show --allow-root-user # served certificate, every known one by expiry
php bin/php/console exp:velocity ssl show --json --allow-root-user # for monitoring: watch daysLeft
php bin/php/console exp:velocity ssl renew --apply example.com --allow-root-userEin CA-Zertifikat mit 90 Tagen Laufzeit wird erneuert, wenn noch etwa 30 Tage übrig sind; eines mit weniger als 14
verbleibenden Tagen bedeutet also, dass die Erneuerung seit mehr als zwei Wochen fehlschlägt; der letzte Fehler, den
ssl show zusammen mit dem ACME-Zustand ausgibt, sagt warum. Lassen Sie NTP laufen: Zertifikate werden gegen die
Systemuhr geprüft. Der Reiter SSL des Control Panels zeigt dasselbe und kann vom Browser aus erneuern und neu laden
(Abschnitt 8.3.13).
| Symptom | Ursache | Abhilfe |
|---|---|---|
status meldet, HTTPS sei aus | Enabled ist nicht true, oder eine genannte Datei existiert nicht | die Pfade mit ls -l prüfen; config get HTTPSSettings Certificate |
| der Browser warnt vor dem Zertifikat | der selbstsignierte Ersatz wird ausgeliefert: das echte Paar ist abgelaufen, passt nicht zusammen oder ist noch nicht ausgestellt | ssl show; das Start-Log nennt den Grund |
ACME Invalid response from http://.../.well-known/acme-challenge/... | Port 80 erreicht diesen Server nicht | Port 80 öffnen oder acme.webroot für den Server setzen, dem er gehört |
none of the certificates belongs to the private key | Schlüssel und Zertifikat stammen aus verschiedenen Anträgen | den Schlüssel verwenden, für den das Zertifikat ausgestellt wurde |
8.3.10 Der Konfigurationsbaum: /etc/vc im Debian-Stil
Die Konfiguration von Velocity auf der Platte spiegelt Debians /etc/apache2, sodass ein Administrator, der Apache
kennt, alles an der erwarteten Stelle findet:
/etc/vc/ Velocity's overlay on the engine's base tree /etc/qbix
├── vc.conf settings shared by every site (apache2.conf)
├── ports.conf listen ports (ports.conf)
├── envvars environment of the server process (envvars)
├── conf-available/*.conf shared snippets -> conf-enabled/ (symlinks)
├── mods-available/*.conf engine modules: http2, cache, ... -> mods-enabled/ (symlinks)
├── sites-available/*.conf one file per installation -> sites-enabled/ (symlinks)
├── designs/ the server's own page designs
└── ssl/ certificates (self-signed, imported, ACME), in the directory the server runs with
/var/lib/vc/sites/<site>.json what is known about each installationWelches Verzeichnis. [LayoutSettings] ConfDir=auto verwendet /etc/vc, wenn es existiert oder angelegt werden
kann (also wenn exp:velocity als root läuft), sonst ein vorhandenes /etc/qbix, sonst var/vc/qbix/etc innerhalb
der Installation. disabled verwendet nur eine einzige generierte Datei (var/tmp/velocity-server.json, die in jedem
Fall geschrieben wird, sodass auch eine ältere Engine daraus starten kann); ein Pfad benennt ein Verzeichnis.
[LayoutSettings] StateDir=auto legt die Metadaten der Website in /var/lib/vc ab, wenn die Konfiguration in
/etc/vc liegt, sonst in var/vc/qbix/lib. Der Name der Website in sites-available ist
[LayoutSettings] SiteName, standardmäßig der Host aus site.ini [SiteSettings] SiteURL.
Das Overlay. /etc/qbix ist der eigene Basisbaum der Engine (so wie ihn das Betriebssystempaket installiert);
/etc/vc wird von der vc-Distribution der Engine darübergelegt und nach ihm geladen, sodass es gewinnt.
Ladereihenfolge, das Spätere gewinnt (eine tiefe Zusammenführung, wie die Includes von Apache):
- Voreinstellungen der Engine, dann die
config/server.jsonder Anwendung vc.confports.confmods-enabled/*in Namensreihenfolgeconf-enabled/*in Namensreihenfolge- die Site-Datei,
sites-enabled/<site>.conf - Kommandozeilen-Optionen (
--port,--workers, ...)
Wer was schreibt. velocity.ini bleibt die Quelle. Bei jedem start und restart (und bei layout migrate)
schreibt exp:velocity die Datei ports.conf, die von ihm verwalteten Moduldateien und
sites-available/<site>.conf (Modus 0600: Sie enthält Zertifikatspfade und das Dashboard-Token). Generierte Dateien
tragen "_generated": "exp:velocity"; entfernen Sie diese Markierung aus einer Datei, wird sie nie wieder
überschrieben, wie eine conffile von dpkg. vc.conf, envvars und alles andere, was Sie hinzufügen, werden einmal
angelegt und danach nur noch gelesen. Bevor der Baum verwendet wird, werden die generierten Teile zusammengeführt und
mit der einzelnen Konfiguration verglichen, die sie ersetzen; schlägt diese Prüfung fehl, wird der Server aus der
einzelnen Datei gestartet, und das Log nennt den Grund. Absichtlich vorgenommene Abweichungen (ein deaktiviertes Modul,
ein aktiviertes Snippet) werden berücksichtigt und in der Startmeldung genannt.
Aktivieren und deaktivieren, wie mit a2ensite, a2enconf und a2enmod:
php bin/php/console exp:velocity layout --allow-root-user # every path, what is enabled, the files in use
php bin/php/console exp:velocity layout migrate --apply --allow-root-user # write the tree now
php bin/php/console exp:velocity site enable --apply <name> --allow-root-user # sites-enabled/<name>.conf -> ../sites-available/
php bin/php/console exp:velocity site disable --apply <name> --allow-root-user # removes only the symlink
php bin/php/console exp:velocity conf enable --apply|disable <name> --allow-root-user
php bin/php/console exp:velocity mod enable --apply|disable <name> --allow-root-user
php bin/php/console exp:velocity ctl configtest --allow-root-user # the engine's own check of the treeDer Baum gehört zur Engine qbix. Bei frankenphp ist die Konfiguration eine generierte Caddyfile und bei php ein
Router-Skript; dort listet layout diese Dateien auf, und site|conf|mod verweigern den Dienst.
8.3.11 Velocity als Dienst betreiben
exp:velocity hat keinen Befehl, der einen Systemdienst für den Bootvorgang installiert. Es gibt zwei Wege:
Die eigenen Units der Engine. Das Engine-Paket liefert Beispiele mit:
vendor/se7enxweb/exponential-velocity/service/qbixserver.service(systemd) undcom.qbix.server.plist(launchd), mit einerREADME.md, für einen einfachen Qbix-Server, der mit--root,--portund--pidgestartet wird;vendor/se7enxweb/exponential-velocity/packaging/systemd/exponential-velocity.service, die Unit des Betriebssystempakets (User=qbix,AmbientCapabilities=CAP_NET_BIND_SERVICE,EnvironmentFile=-/etc/default/exponential-velocity, Härtung mitNoNewPrivileges,ProtectSystem,ProtectHome,PrivateTmp).
Beide starten die Engine direkt und umgehen damit, was exp:velocity hinzufügt: die generierte Site-Datei in
/etc/vc, KeepGlobals, [PHPSettings] IniOptions[] (OPcache, APCu), den Worker-Benutzer, das Engine-Archiv und die
Instanzen.
Eine Unit, die exp:velocity ausführt (abgeleitet). Die folgende Unit wird nicht mitgeliefert; sie ist aus dem
abgeleitet, was expVelocity::start() tut (es startet den Server abgekoppelt und kehrt zurück, sobald der Port
antwortet, wobei die PID in var/vc/qbix/run/server.pid hinterlegt wird), und aus den obigen Befehlen. Sie belässt
jede Einstellung in velocity.ini:
# /etc/systemd/system/exponential-velocity-example.service
[Unit]
Description=Exponential Velocity for example.com
After=network-online.target mysqld.service
Wants=network-online.target
[Service]
Type=forking
WorkingDirectory=/var/www/example.com
ExecStart=/usr/bin/php bin/php/console exp:velocity start --allow-root-user
ExecStop=/usr/bin/php bin/php/console exp:velocity stop --allow-root-user
ExecReload=/usr/bin/php bin/php/console exp:velocity graceful --allow-root-user
PIDFile=/var/www/example.com/var/vc/qbix/run/server.pid
TimeoutStartSec=90
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetsystemctl daemon-reload
systemctl enable --now exponential-velocity-example
systemctl status exponential-velocity-exampleHinweise: Sie läuft als root, damit der Server die Ports 80 und 443 binden und den Schlüssel lesen kann; die Worker
wechseln trotzdem zu [ServerSettings] User und Group. Passen Sie After= an Ihren Datenbankdienst an. Bei
Instances über 1 benennt PIDFile nur Instanz 0. Kombinieren Sie sie nicht mit der Unit des Betriebssystempakets für
dieselben Ports.
8.3.12 Logs
Alles, was Velocity schreibt, liegt unter var/vc/, ein Verzeichnis je Engine:
var/vc/
├── qbix/
│ ├── etc/ the configuration tree when /etc/vc is not used
│ ├── lib/ site metadata when /var/lib/vc is not used
│ ├── log/ <siteaccess>-access.log, <siteaccess>-error.log, velocity-layout.log ([LogSettings] Dir)
│ └── run/ server.pid, console.log (PidFile, LogFile)
├── frankenphp/ bin/ caddy/ tls/ log/ run/
└── php/ log/server.log, run/server.pidEinstellung ([LogSettings]) | Ausgeliefert | Bedeutung |
|---|---|---|
Enabled | enabled | ohne sie zeichnet der Server überhaupt nichts auf |
Dir | var/vc/qbix/log | das Log-Verzeichnis der Engine qbix |
AccessName, ErrorName | leer | leer benennt die Dateien nach dem Standard-Siteaccess (site-access.log) |
Format | combined | das Combined-Format von Apache; qbix ergänzt die Antwortzeit; common; oder ein Format-String |
FileMode, DirMode | 0640, 0750 | ein Zugriffslog nennt Besucher; es ist nicht für jedes Konto lesbar gedacht |
Bei der Rotation wird das Datum vor die Dateiendung gesetzt (site-access.2026-09-24.log). console.log enthält, was
der Prozess ausgibt, einschließlich der Startzeilen (Workers as: ..., tls: certificate ready ...). Die eigenen Logs
des Kernels bleiben wie unter jedem Server in var/<site>/log/.
8.3.13 Das Dashboard und das Control Panel
Der Server beantwortet einige eigene Seiten unterhalb von /Q/, unabhängig von der Anwendung:
| Ansicht | Was | Wer sie öffnen darf (so wie exp:velocity es konfiguriert) |
|---|---|---|
/Q/dashboard | laufende Anfragen, Worker, Speicher, Statuscodes | dieser Rechner; von anderswo mit [DashboardSettings] Token |
/Q/stats, /Q/metrics, vollständiges /Q/health | Kennzahlen, Prometheus-Metriken, Statusbericht | dieser Rechner; von anderswo mit dem Token oder der Panel-Anmeldung |
/Q/phpinfo | phpinfo() einschließlich der Prozessumgebung | dieser Rechner; von anderswo nur mit dem Token oder einer Panel-Sitzung, nie über Remote=enabled |
/Q/panel | Control Panel: Domains, Zertifikate, Cache, Logs, Worker, Einstellungen | dieser Rechner, dann das Panel-Passwort |
/Q/health (nur Status), /Q/docs | „ok“, Dokumentation | alle |
Ein Token ist eine beliebige lange Zufallszeichenkette, zum Beispiel von openssl rand -hex 24; setzen Sie es mit
exp:velocity config set DashboardSettings Token <value> und übergeben Sie es als ?token=... oder als
Authorization: Bearer .... [DashboardSettings] Remote=enabled gibt die Kennzahlen ohne Token aus der Ferne frei;
verwenden Sie das nur auf einem Port, den bereits eine Firewall einschränkt. Um das Panel eines entfernten Servers zu
erreichen, verwenden Sie einen SSH-Tunnel zum eigenen Port des Servers.
Der erste Besuch von /Q/panel legt das Panel-Passwort fest (mindestens 16 Zeichen nach den Stärkeregeln der Engine;
bcrypt; fehlgeschlagene Anmeldungen sperren die Adresse mit wachsenden Pausen). Auf einem Rechner, der aus dem
Internet erreichbar ist, legen Sie es sofort fest. Sein Speicher darf weder für die Gruppe noch für andere beschreibbar
sein, sonst sperrt sich das Panel selbst; qbixctl panel:check der Engine zeigt den Grund. Einzelheiten:
Velocity-Control-Panel.
8.3.14 Eine Änderung bereitstellen: exp:velocity deploy
Worker halten Klassen, INI-Werte und kompilierte Templates im Speicher, daher erreicht eine geänderte PHP-Klasse, ein geänderter Operator oder eine geänderte INI-Datei sie erst nach einem Neustart, und Caches, die gerenderte Ausgaben enthalten, müssen geleert werden, nachdem der neue Code läuft, sonst wird die alte Ausgabe erneut gecacht. Ein einziger Befehl erledigt das in der richtigen Reihenfolge:
php bin/php/console exp:velocity deploy --dry-run --allow-root-user # what it would do, nothing else
php bin/php/console exp:velocity deploy --allow-root-user # the usual case
php bin/php/console exp:velocity deploy --kernel --allow-root-user # a kernel class was added or renamed| # | Schritt | Von Hand |
|---|---|---|
| 1 | Autoloads der Extensions | php bin/php/ezpgenerateautoloads.php -e |
| 2 | Autoloads des Kernels, nur mit --kernel (beschränkt auf kernel/ und lib/) | php bin/php/ezpgenerateautoloads.php -k |
| 3 | INI-Caches | php bin/php/ezcache.php --clear-tag=ini |
| 4 | Caches für template, template-override, translation und design_base | --clear-id=<id>, eine je Aufruf |
| 5 | Engine-Archiv, wenn Velocity aus einem solchen läuft (nur neu gebaut, wenn sich darin etwas geändert hat) | php bin/php/console exp:phar build |
| 6 | PHP-FPM neu laden | systemctl reload <[DeploySettings] PhpFpmService> |
| 7 | Velocity neu starten, wenn er läuft | exp:velocity restart |
| 8 | Caches für content, exphttpcache, (--packer: ezjscore-packer,) template-block | --clear-id=<id> |
| 9 | der Antwort-Cache von Velocity | exp:velocity cache clear |
Jeder Schritt gibt PASS, FAIL oder SKIP mit seiner Dauer aus; der erste Fehlschlag beendet den Lauf
(Exit-Status 1), und die nicht ausgeführten Schritte werden als NOT RUN aufgeführt. --dry-run gibt jeden Schritt
mit dem aus, was er tun würde (DRY), und ändert nichts.
Warum diese Reihenfolge: Die Caches, die gerenderte Ausgaben enthalten (View-Cache für Inhalte, HTTP-Cache, Template-Blöcke, der Antwort-Cache), werden erst geleert, nachdem PHP-FPM neu geladen und Velocity neu gestartet wurde. Würden sie früher geleert, würde jede in der Zwischenzeit angefragte Seite vom alten Code gerendert und erneut gecacht, und die Änderung sähe aus, als hätte sie nicht funktioniert.
Einige Schritte entscheiden selbst, dass sie nichts zu tun haben, und melden das:
- Engine-Archiv (Schritt 5) läuft nur, wenn Velocity aus einem Archiv läuft (
EnginePhar, Abschnitt 8.3.15) und gestartet ist. Dann wird zuerst jede Datei geparst, die ins Archiv kommt, sodass eine Kernel-Datei, die sich nicht parsen lässt, das Deploy anhält, während PHP-FPM und Velocity noch den alten Code ausführen. Ohne Archiv gibt es diese Prüfung nicht: Führen Siephp -lfür das aus, was Sie geändert haben. - Velocity neu starten (Schritt 7) startet nur einen laufenden Server neu. Ein angehaltener bleibt angehalten: Ein Deploy bringt die laufenden Dienste auf den neuesten Stand, entscheidet aber nicht, welche laufen sollen.
- PHP-FPM neu laden (Schritt 6) wird mit einem Hinweis übersprungen, wenn kein Pool gefunden wurde, wenn er nicht
als root ausgeführt wird oder wenn der Rechner kein
systemctlhat.
Optionen: --kernel, --no-autoload, --no-fpm, --no-velocity, --rebuild-phar, --packer (die gepackten
Skripte und Styles zusammen mit den Template-Blöcken leeren; nur nötig, wenn sich eine Server-Funktion des Packers
oder deren Einstellungen geändert haben), --engine=<name>, --dry-run, --json.
[DeploySettings] PhpFpmService benennt das PHP-FPM, das neu geladen werden soll, sodass auch ein Apache oder nginx
neben Velocity den neuen Code ausführt: auto (die Voreinstellung) findet die Pool-Konfiguration, die nach der
Hosting-Domain der Installation benannt ist oder deren Verzeichnis nennt, in /opt/plesk/php/*/etc/php-fpm.d,
/etc/php-fpm.d, /etc/php/*/fpm/pool.d und /etc/opt/remi/php*/php-fpm.d; ein Unit-Name (oder mehrere, durch
Kommas getrennt) benennt es direkt; disabled, wenn Velocity die Website allein ausliefert. Der Schritt ist ein
sanftes systemctl reload und braucht root; unter jedem anderen Benutzer wird er mit einem Hinweis übersprungen.
Für eine Änderung an einem Template oder Stylesheet ist kein Neustart nötig: Leeren Sie wie gewohnt die
Template-Caches und führen Sie exp:velocity cache clear aus. exp:velocity graceful führt den Server neu aus und
behält dabei den lauschenden Socket, sodass ein Neustart keine Anfrage verliert.
8.3.15 Das Engine-Archiv: engine.phar
Der Kernel kann aus einem einzigen Archiv laufen, dist/engine.phar, statt aus den Dateien in kernel/, lib/ und
autoload/. Das lohnt sich für die Verteilung und um zu wissen, dass die Engine genau das ausführt, was gebaut wurde;
gemessen ist es nicht schneller, sobald OPcache warm ist.
php bin/php/console exp:phar build # build (only when something changed; --force always)
php bin/php/console exp:phar check # is the archive current?
php bin/php/console exp:phar info
php bin/php/console exp:velocity config set --apply ServerSettings EnginePhar enabled
php bin/php/console exp:velocity restartZum Schreiben eines Archivs muss phar.readonly von PHP ausgeschaltet sein. Die Konsole startet jeden Befehl in einem
frischen PHP, daher erreicht ein php -d phar.readonly=0 vor bin/php/console den Befehl nie; exp:phar build prüft
deshalb zuerst, ob das Archiv aktuell ist, und startet sich, wenn es schreiben muss, selbst noch einmal mit
-d phar.readonly=0. Von Hand muss nichts gesetzt werden.
[ServerSettings] EnginePhar nimmt disabled (die Dateien auf der Platte, die Voreinstellung), enabled
(dist/engine.phar) oder einen Pfad. Ein Pfad, der nicht existiert, bricht den Start ab, statt stillschweigend
zurückzufallen. Ist ein Archiv in Gebrauch, bauen start, restart und graceful es zuerst neu, wenn eine Datei in
kernel/, lib/ oder autoload/ hinzugefügt, entfernt oder geändert wurde (andernfalls
engine.phar is current, not rebuilt); --rebuild-phar erzwingt es. Siehe
Engine-Archiv (phar).
8.3.16 Befehlsreferenz
| Befehl | Tut |
|---|---|
exp:velocity status (Standardverb) | Übersicht über jede Engine, dann Einzelheiten; --json, --all, --engine= |
exp:velocity start / stop / restart | wie benannt; start wartet, bis der Port antwortet |
exp:velocity graceful | führt den Server neu aus und behält den lauschenden Socket; keine verlorenen Anfragen |
exp:velocity kill | anhalten ohne Rückfrage, für einen festgefahrenen Worker |
exp:velocity deploy | alles, was eine PHP-Änderung braucht, in der richtigen Reihenfolge (Abschnitt 8.3.14) |
exp:velocity command | die Befehlszeile ausgeben, die ausgeführt würde, und beenden |
exp:velocity config list|get|set|unset|paths | Werte von velocity.ini lesen und schreiben |
exp:velocity cache clear|stats | der Antwort-Cache |
exp:velocity layout [migrate] | der Konfigurationsbaum und jede Datei, die der Server verwendet |
exp:velocity site|conf|mod enable|disable <name> | die a2ensite-Familie |
exp:velocity ssl show|renew [host...] | Zertifikate (nur qbix; die anderen Engines beziehen ihr Zertifikat aus [HTTPSSettings]). show ist die Standardaktion. Nicht in --help aufgeführt, aber akzeptiert |
exp:velocity ctl <args> | qbixctl der Engine mit dem Baum, der Website und der PID-Datei dieser Installation (ctl status, ctl configtest, ...) |
exp:velocity ext check|list|plan|install-hint|build | PHP-Extensions, die die Engine erwartet |
exp:velocity install | FrankenPHP: die Binärdatei herunterladen und prüfen (--force, --from=<file>, --check, --trust-github-digest); qbix: nichts zu tun |
Optionen werden in GNU- und BSD-Schreibweise akzeptiert (--keep-global V, -keep-global=V, -json); alles nach
-- wird unverändert an die Engine weitergereicht. exp:velocity --help gibt die vollständige Liste aus. Eine Option,
die zu einem anderen Verb gehört, wird mit einer Meldung abgelehnt, die die Verben nennt, zu denen sie gehört, zum
Beispiel velocity: --dry-run goes with deploy oder
velocity: --rebuild-phar goes with start, restart, graceful and deploy; ein unbekanntes Verb listet die gültigen auf.
8.4 FrankenPHP
FrankenPHP ist der Webserver Caddy mit eingebautem PHP, als eine einzige Binärdatei. Velocity lädt ihn herunter, prüft
ihn und steuert ihn mit denselben Befehlen. Er läuft im klassischen Modus: ein Pool von PHP-Threads, wobei jede Anfrage
wie unter PHP-FPM von einem sauberen Zustand aus startet, daher gelten ForkPerRequest, KeepGlobals und der
Antwort-Cache hier nicht.
php bin/php/console exp:velocity config set --apply ServerSettings Engine frankenphp --allow-root-user
php bin/php/console exp:velocity install --allow-root-user # optional: start installs it when missing
php bin/php/console exp:velocity start --allow-root-user- Die Binärdatei.
installholt das Release-Asset für diesen Rechner zu[FrankenPHPSettings] Version(ausgeliefert1.12.7) und weist es zurück, sofern seine SHA-256-Prüfsumme nicht mit der daneben festgelegten ZeileSha256[<asset>]übereinstimmt. Es wird invar/vc/frankenphp/bin/abgelegt.Variantwählt den Linux-Build (gnu, die Voreinstellung, lädt.so-Extensions;musl;mimalloc).BinaryPathbenennt einen eigenen Build.install --from=<file>installiert auf einem Rechner ohne Zugang zu GitHub eine kopierte Datei, die auf dieselbe Weise geprüft wird. - PHP-Einstellungen. Die Binärdatei liest keine
php.inides Rechners, daher liefert[FrankenPHPSettings] IniOptions[]display_errors=Off,log_errors=On,memory_limit=512M,opcache.enable=1und die Upload-Limits mit;PHPIniFilebenennt stattdessen eine eigenephp.ini. - Threads.
[FrankenPHPSettings] Workersist die Anzahl der PHP-Threads; leer bedeutet die Voreinstellung von FrankenPHP, die doppelte Anzahl der CPU-Kerne; mehr Threads als das erwiesen sich unter hoher Last als langsamer.SpareWorkersfügt unter Last Threads hinzu. - HTTPS. Standardmäßig an (
HTTPS=enabled) aufHTTPSPort(8444) neben HTTP aufPort(8089). Es verwendet[HTTPSSettings] CertificateundKey, wenn beide gesetzt sind; sind beide leer, erzeugt es ein selbstsigniertes Zertifikat für den Rechner invar/vc/frankenphp/tls/(ein Jahr gültig) und erneuert es einen Monat vor Ablauf. Eine öffentliche Website benennt ihr Zertifikat; führen Sie nach dem Ersetzen der Dateienexp:velocity gracefulaus.start --no-httpsundstart --httpsentscheiden für einen einzelnen Start (nur mitstart,restartundgraceful);HTTPS=disabledschaltet es ab.exp:velocity sslgehört zur Engineqbixund verweigert hier den Dienst. - Komprimierung.
[FrankenPHPSettings] Compression(zstd br gzip) ist das, was Caddy den Clients anbietet; Caddy komprimiert nichts, solange es nicht dazu angewiesen wird.disabledschaltet es ab. - Konfiguration.
var/vc/frankenphp/run/Caddyfilewird bei jedemstart,gracefulundrestarterzeugt und mitfrankenphp validategeprüft, bevor sie die alte ersetzt. Ihr Routing ist das von.htaccess_root; sie verwendet nichtphp_server, das jede vorhandene Datei ausliefern würde. Eigene Direktiven kommen in eine Datei, dieSiteIncludebenennt.exp:velocity ctl caddyfilegibt die Konfiguration aus. - Steuerung.
stopundgracefulverwenden die Admin-API von Caddy über den nur für den Eigentümer zugänglichen Socketvar/vc/frankenphp/run/admin.sock;gracefullädt die Konfiguration neu, ohne eine Verbindung abzubrechen. - Logs.
var/vc/frankenphp/log/access.logunderror.log, im JSON-Format von Caddy.
Einzelheiten: FrankenPHP und Velocity-Engines.
8.5 Apache mit PHP-FPM
Apache mit mod_rewrite, mod_proxy_fcgi und einem PHP-FPM-Pool ist das klassische Setup und braucht keinen eigenen
dauerhaft laufenden Prozess.
8.5.1 Schritt für Schritt
Die Rewrite-Regeln aktivieren. Sie werden als
.htaccess_rootausgeliefert; kopieren Sie die Datei, statt sie zu verschieben, damit ein Update eine neue Version mitbringen kann:./console exp:setup:htaccess --apply # oder von Hand: cp .htaccess_root .htaccessVerwenden Sie stattdessen
.htaccess_root_staticnur, wenn Sie einen generierten statischen Cache ausliefern (es ist.htaccess_rootmit zusätzlichen Regeln zum Ausliefern des statischen Caches):./console exp:setup:htaccess --static --apply. Der Befehl kopiert mit dem Modus der Vorlage (und, als root mit--allow-root-user, mit ihrem Eigentümer), zeigt einen Diff und lehnt ab, wenn bereits eine abweichende.htaccessvorhanden ist, und sichert die alte Datei nachvar/backup/setup/<time>/, bevor--force --applysie ersetzt../console exp:setup:statuszeigt, von welcher Vorlage die aktuelle.htaccesseine Kopie ist. Siehe .htaccess und config.php von der Konsole aus einrichten.Die Module laden.
mod_rewrite,mod_proxyundmod_proxy_fcgi(Debian:a2enmod rewrite proxy_fcgi); für HTTPSmod_ssl, für HTTP/2mod_http2.Den virtuellen Host anlegen. Passen Sie die Pfade und den PHP-FPM-Socket an Ihr System an:
<VirtualHost *:80> ServerName example.com ServerAlias www.example.com # The installation root, where index.php is DocumentRoot /var/www/example.com DirectoryIndex index.php <Directory /var/www/example.com> Options FollowSymLinks # Lets Apache read the .htaccess created in step 1 AllowOverride All Require all granted </Directory> # Every PHP script goes to the PHP-FPM pool of this site <FilesMatch \.php$> SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost" </FilesMatch> </VirtualHost>Wenn Sie lieber auf
.htaccessverzichten (AllowOverride Nonespart einen Dateizugriff je Verzeichnis), kopieren Sie die Regeln von.htaccess_rootin den<Directory>-Block; innerhalb von<Directory>behalten sie ihre Form. Im Serverkontext (außerhalb von<Directory>) braucht jedes Muster einen führenden Schrägstrich, wie indoc/eng-us/examples/ezpublish.conf, einem vollständigen virtuellen Host (HTTP-Weiterleitung, HTTPS, HTTP/2, PHP-FPM, Header) mit den Regeln der.htaccess_rootdieser Release im Serverkontext (Virtueller Host für Apache). Vergleichen Sie Ihre Kopie nach jedem Upgrade mit.htaccess_rootund übernehmen Sie neue Regeln.HTTPS. Fügen Sie einen virtuellen Host
*:443mit demselben Inhalt hinzu, ergänzt um:SSLEngine on SSLCertificateFile /etc/ssl/example.com/fullchain.pem SSLCertificateKeyFile /etc/ssl/example.com/privkey.pem Protocols h2 http/1.1und beziehen Sie das Zertifikat mit certbot oder Ihrem Hosting-Panel. Leiten Sie Port 80 im Host
*:80auf HTTPS weiter (Redirect permanent / https://example.com/), sobald HTTPS funktioniert.Prüfen und neu laden:
apachectl configtest # Syntax OK systemctl reload apache2 # httpd on Red Hat style systems curl -sI https://example.com/ | head -1Ein 404 für jede Seite bedeutet, dass
.htaccessnicht gelesen wird (AllowOverride) odermod_rewriteaus ist; ein 500 bedeutet, dass ein Blick in die Fehlerlogs von Apache und PHP-FPM fällig ist.Sicherheits-Header sendet der Kernel auf seinen Seiten (
site.ini [HTTPHeaderSettings] SecurityHeaders[]). Für statische Dateien fügen Sie dieselben mitmod_headershinzu, wenn Sie sie auch dort haben möchten; siehe Kapitel 13.
8.5.2 PHP-FPM
Der Pool führt PHP unter dem Benutzer der Website aus. Für Exponential relevante Einstellungen (in der Pool-Datei oder
in php.ini): memory_limit (mindestens 256M; mehr für große Importe), max_execution_time, upload_max_filesize
und post_max_size (Ihr größter Upload), OPcache eingeschaltet. Nach einer Änderung an einer PHP-Klasse, einem
Operator oder einer INI-Datei laden Sie den FPM-Master neu, der die Website ausliefert:
systemctl reload php-fpm # the distribution's single PHP
php bin/php/console exp:velocity deploy --no-velocity --allow-root-user # finds the right one and clears caches in orderAuf Rechnern mit mehreren PHP-Versionen ist der Master, der die Website ausliefert, oft nicht derjenige namens
php-fpm. Finden Sie ihn über seine Pool-Datei: [DeploySettings] PhpFpmService=auto tut genau das
(deploy --dry-run zeigt, was es gefunden hat und warum).
8.5.3 Plesk
Plesk erzeugt den virtuellen Host selbst; bearbeiten Sie seine Dateien nicht. In Plesk:
- richten Sie das Document Root der Domain auf das Installationsverzeichnis (das Verzeichnis mit
index.php); - wählen Sie in den PHP-Einstellungen „FPM-Anwendung, bereitgestellt von Apache“ und die PHP-Version;
- behalten Sie
.htaccess(kopiert aus.htaccess_root, zum Beispiel mit./console exp:setup:htaccess --apply); das Apache von Plesk liest sie; - installieren Sie das Zertifikat in Plesk (über seine Let's-Encrypt-Erweiterung oder ein eigenes) und schalten Sie die Weiterleitung auf HTTPS ein.
Plesk benennt jeden Pool nach der Domain in /opt/plesk/php/<version>/etc/php-fpm.d/<domain>.conf, ausgeliefert von
der systemd-Unit plesk-php<XY>-fpm (zum Beispiel plesk-php85-fpm). systemctl restart php-fpm startet einen
anderen Master neu, den keine Plesk-Website verwendet. Laden Sie den richtigen neu (systemctl reload plesk-php85-fpm)
oder lassen Sie exp:velocity deploy ihn finden: auto erkennt die Benennung von Plesk an der Hosting-Domain im Pfad
der Installation (/var/www/vhosts/<domain>/...).
8.6 nginx mit PHP-FPM
Diese Konfiguration ist abgeleitet, nicht mitgeliefert. Exponential liefert in seinem Repository keine
nginx-Konfiguration mit. Der folgende Server-Block ist eine Übertragung von .htaccess_root (der Version in dieser
Release) in nginx-Direktiven, Regel für Regel, nach der eigenen Dokumentation von nginx zu location, try_files,
return und fastcgi_pass. Testen Sie ihn auf Ihrer Website, bevor Sie sich darauf verlassen, und vergleichen Sie ihn
nach jedem Upgrade mit .htaccess_root.
server {
listen 80;
server_name example.com www.example.com;
# The installation root, where index.php is
root /var/www/example.com;
index index.php;
# Uploads: nginx's default limit is 1 MB
client_max_body_size 64m;
# 1. No dot file or dot directory, anywhere; .well-known stays reachable
location ~ (^|/)\.(?!well-known(/|$)) {
return 404;
}
# 2. No script below the root runs because its path was asked for
# (.htaccess_root answers 404 only when the file exists; this answers 404 always)
location ~ ^/.+/[^/]+\.(php[0-9]?|phtml|phar)$ {
return 404;
}
# 3. Front controllers
location ^~ /api/ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index_rest.php;
fastcgi_param SCRIPT_NAME /index_rest.php;
fastcgi_pass unix:/run/php-fpm/www.sock;
}
location = /index_rest.php {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index_rest.php;
fastcgi_param SCRIPT_NAME /index_rest.php;
fastcgi_pass unix:/run/php-fpm/www.sock;
}
location ~ ^/([^/]+/)?content/treemenu {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index_treemenu.php;
fastcgi_param SCRIPT_NAME /index_treemenu.php;
fastcgi_pass unix:/run/php-fpm/www.sock;
}
# 4. Files served as they are (the "- [L]" rules of .htaccess_root);
# a listed path that does not exist is a 404, as under Apache
location ~ ^/var/([^/]+/)?storage/images(-versioned)?/ { try_files $uri =404; }
location ~ ^/var/([^/]+/)?storage/original/image/.+\.(png|jpe?g|gif|webp|svg)$ { try_files $uri =404; }
location ~ ^/var/([^/]+/)?storage/pdf/[A-Za-z0-9][A-Za-z0-9._-]*\.pdf$ { try_files $uri =404; }
location ~ ^/var/([^/]+/)?cache/(texttoimage|public)/ { try_files $uri =404; }
# With site.ini [FileSettings] CacheVarDir=var_cache (multi-site hosting, see
# doc/eng-us/features/6.0/multi-site-log-and-cache-paths.md):
#location ~ ^/var_cache/([^/]+/)?cache/(texttoimage|public)/ { try_files $uri =404; }
location ~ ^/design/[^/]+/(stylesheets|images|javascript|fonts)/ { try_files $uri =404; }
location ~ ^/share/icons/ { try_files $uri =404; }
location ~ ^/extension/[^/]+/icons/[A-Za-z0-9_/-]+\.(svg|png|gif)$ { try_files $uri =404; }
location ~ ^/extension/[^/]+/design/[^/]+/(stylesheets|flash|images|lib|javascripts?|fonts|vendor|media)/ { try_files $uri =404; }
location ~ ^/packages/styles/.+/(stylesheets|images|javascript)/[^/]+/ { try_files $uri =404; }
location ~ ^/packages/styles/.+/thumbnail/ { try_files $uri =404; }
location ~ ^/var/storage/packages/.+\.(png|jpe?g|gif|webp)$ { try_files $uri =404; }
location = /favicon.ico { try_files $uri =404; }
location = /robots.txt { try_files $uri =404; }
location = /index.js { try_files $uri =404; }
location = /sw.js { try_files $uri =404; }
location = /w3c/p3p.xml { try_files $uri =404; }
# 5. Everything else goes to index.php, with the original REQUEST_URI
location / {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_param SCRIPT_NAME /index.php;
fastcgi_pass unix:/run/php-fpm/www.sock;
}
}Wie die Zuordnung funktioniert und warum die Reihenfolge so ist:
- nginx wählt eine Location nach seiner eigenen Rangfolge, nicht nach der Reihenfolge in der Datei: zuerst exakte
Treffer (
=), dann das längste^~-Präfix, dann reguläre Ausdrücke in der Reihenfolge ihres Auftretens, dann das längste einfache Präfix. Die Regeln für Punkt-Dateien und Skripte sind daher die ersten regulären Ausdrücke, so wie sie die ersten Regeln von.htaccess_rootsind;/ist das einfache Präfix, das den Rest auffängt, wie die abschließendeRewriteRule .* index.php. - Die Regeln von
.htaccess_rootfür/api/und das Baummenü schreiben auf einen Front-Controller um. Hier wird der Front-Controller inSCRIPT_FILENAMEbenannt, und die Anfrage wird nicht umgeschrieben, sodassREQUEST_URI(vonfastcgi_paramsaus$request_urigesetzt) weiterhin die Adresse enthält, die der Besucher angefragt hat, genau wie bei Apache. - Eine
.phpim Wurzelverzeichnis, die kein Front-Controller ist (zum Beispiel/config.php), erreichtlocation /und wird vonindex.phpbeantwortet, nie ausgeführt: wie bei.htaccess_root. - Die statischen Locations haben kein
fastcgi_pass, daher läuft dort kein PHP; die Skript-Regel davor stellt sicher, dass eine.phpunterhalb eines Asset-Verzeichnisses auch nicht als Text gesendet wird. fastcgi_paramsaus den nginx-Paketen übergibtHTTPS, wenn die Verbindung TLS ist, und genau das prüft Exponential zuerst.- Nicht übertragen: die auskommentierten Favicon- und Debug-Zeilen von
.htaccess_rootsowie/design/standard/images/favicon.ico, das die Design-Regel bereits abdeckt.
Für HTTPS fügen Sie listen 443 ssl; (und http2 on; ab nginx 1.25.1), ssl_certificate und ssl_certificate_key
hinzu sowie einen separaten server auf Port 80, der 301 https://$host$request_uri zurückgibt. Prüfen Sie mit
nginx -t und laden Sie mit systemctl reload nginx neu. Sicherheits-Header für statische Dateien:
add_header ... always; (Kapitel 13).
8.7 Dateiberechtigungen und Eigentümer
8.7.1 Was beschreibbar sein muss
Der Benutzer, der PHP für die Website ausführt (der Benutzer des PHP-FPM-Pools, der Worker-Benutzer von Velocity oder
der FrankenPHP-Prozess), muss in diese Verzeichnisse schreiben können; es ist die Liste, die der Setup-Assistent prüft
(settings/setup.ini [directory_permissions]):
| Verzeichnis | Warum |
|---|---|
var/ und darunter: var/cache, var/log, var/storage, var/autoload, var/<site>/... | Caches, kompilierte Templates, Logs, hochgeladene Dateien und Bildvarianten, Autoload-Arrays |
settings/, settings/override, settings/siteaccess, settings/siteaccess/<admin> | der Setup-Assistent und die Administration schreiben Einstellungen |
design/, extension/ | der Setup-Assistent und die Paketinstallation schreiben dorthin |
Nach der Installation können Sie den Schreibzugriff auf design/ und extension/ wieder entziehen, wenn nichts Pakete
über die Administration installiert; settings/ bleibt beschreibbar, wenn Administratoren Einstellungen im Browser
ändern (und die Prüfung settings_permission des Setups erwartet das).
Alles andere (kernel, lib, vendor, index.php) muss nur lesbar sein. Die Systemprüfung gibt für Ihren Rechner Befehle
in dieser Form aus:
sudo chown -R example:example design extension settings var
sudo chmod -R ug+rwx design extension settings var8.7.2 Ein Benutzer oder eine Gruppe
Probleme mit Berechtigungen entstehen fast immer dadurch, dass zwei Benutzer dieselben Dateien schreiben: das PHP
des Webservers, die Velocity-Worker, Cronjobs und Kommandozeilen-Skripte. Eine Cache-Datei, die root auf der
Kommandozeile geschrieben hat, kann der Benutzer der Website danach nicht ersetzen, und die Website bricht an seltsamen
Stellen.
owner: example group: example
PHP-FPM pool ----------------+
Velocity workers ([ServerSettings] User/Group)
cronjobs, console scripts ----+---- all write var/ as the same userEmpfohlen, in dieser Reihenfolge:
Führen Sie alles unter dem Benutzer der Website aus. PHP-FPM-Pool
user = example; Velocity[ServerSettings] User=example,Group=example(oder lassen Sie beide leer und den Eigentümer des Document Root entscheiden); Cronjobs aus der Crontab dieses Benutzers (crontab -u example -e) oder mitsudo -u example php runcronjobs.php. Velocity als root zu starten ist in Ordnung: Nur sein Elternprozess bleibt root.Wenn die Benutzer verschieden sein müssen (zum Beispiel
apachevon Apache und ein Deploy-Benutzer), geben Sie ihnen eine gemeinsame Gruppe, machen Sie die beschreibbaren Verzeichnisse für die Gruppe beschreibbar und setzen Sie setgid, damit neue Dateien die Gruppe erben, und verwenden Sie Berechtigungen, die den Schreibzugriff der Gruppe erhalten:sudo chgrp -R example design extension settings var sudo find var settings -type d -exec chmod 2775 {} +# settings/override/site.ini.append.php [FileSettings] StorageDirPermissions=0770 StorageFilePermissions=0660 TemporaryPermissions=0770 LogFilePermissions=0660Die ausgelieferten Werte sind
0777und0666(für alle beschreibbar);site.iniselbst empfiehlt0770und0660mit dem richtigen Benutzer und der richtigen Gruppe, was die gehärtete Wahl ist (Kapitel 13).
Wenn Apache (PHP-FPM) und Velocity dieselbe Installation nebeneinander ausliefern, teilen sie sich var/, die Caches
und die Sitzungen: Geben Sie ihnen denselben Benutzer oder das Setup aus Punkt 2. Testen Sie mit beiden im Betrieb und
sehen Sie sich nach einigen Anfragen den Eigentümer neuer Dateien in var/ an.
8.7.3 Die eigenen Dateien von Velocity
| Pfad | Geschrieben von | Modus |
|---|---|---|
/etc/vc/sites-available/<site>.conf | exp:velocity (root) | 0600 |
ssl/ des Konfigurationsverzeichnisses: private Schlüssel | dem Server | 0600, atomar geschrieben, nie protokolliert |
var/vc/qbix/log/ | dem Server | [LogSettings] FileMode 0640, DirMode 0750 |
var/cache/qbix-reverse/ | dem Server für die Worker | [CacheSettings] FileMode 0640, DirMode 0750 |
Die Verzeichnisse für den Cache und die Vorkomprimierung werden beim Start an den Worker-Benutzer übergeben. Der
Worker-Benutzer muss den Quellbaum der Engine in vendor/ lesen können.
8.8 Hinter einem Reverse Proxy
Velocity braucht keinen vorgeschalteten Proxy: Es liefert HTTPS selbst aus. Ein Proxy ist dennoch die richtige Form,
wenn ein Load Balancer oder CDN TLS bereits terminiert, wenn eine öffentliche Adresse mehrere Dienste trägt oder wenn
der Server als gewöhnlicher Benutzer auf einem hohen Port laufen muss. Das ausgelieferte Host=127.0.0.1 von Velocity
ist genau dafür gemacht: Der Server ist nur vom Rechner selbst aus erreichbar, und nur über den Proxy.
Was Exponential von einem Proxy liest (lib/ezutils/classes/ezsys.php):
- Welchen Proxys geglaubt wird. Die unten genannten weitergeleiteten Header zählen nur, wenn die Gegenstelle der
Verbindung (
REMOTE_ADDR) insite.ini [HTTPHeaderSettings] TrustedProxies[]aufgeführt ist: Adressen und Bereiche, IPv4 und IPv6, standardmäßig127.0.0.1und::1, also ein Proxy auf demselben Rechner. Ein Proxy unter einer anderen Adresse muss hinzugefügt werden, zum BeispielTrustedProxies[]=192.0.2.10oderTrustedProxies[]=10.0.0.0/8. Siehe Weitergeleiteten Headern wird nur von konfigurierten Proxys vertraut. - HTTPS.
eZSys::isSSLNow()prüft zuerst$_SERVER['HTTPS'], dann den Port gegensite.ini [SiteSettings] SSLPort(443), dann, von einem vertrauenswürdigen Proxy,X-Forwarded-Proto: https, dannX-Forwarded-Port, dannX-Forwarded-ServergegenSSLProxyServerName. Ein Proxy, der TLS terminiert, mussX-Forwarded-Protosetzen; dann stimmen die erzeugten URLs und dasSecure-Flag des Sitzungs-Cookies ([Session] CookieSecure=auto). - Der Host.
X-Forwarded-Hostvon einem vertrauenswürdigen Proxy ersetztHost; andernfalls lassen Sie den Proxy den ursprünglichenHostweitergeben (proxy_set_header Host $host,ProxyPreserveHost On). - Die Adresse des Besuchers.
[HTTPHeaderSettings] ClientIpByCustomHTTPHeader=X-Forwarded-ForlässteZSys::clientIP()diesen Header von einem vertrauenswürdigen Proxy lesen, und zwar von rechts: Vertrauenswürdige Proxys werden übersprungen, und die erste andere Adresse ist der Besucher. Einträge, die ein Client vorangestellt hat, werden ignoriert, daher darf ein Proxy anhängen ($proxy_add_x_forwarded_for) oder überschreiben. - Velocity beantwortet diese Fragen, bevor der Kernel die Anfrage sieht; siehe „Velocity hinter einem Proxy“ weiter unten.
Velocity hinter einem Proxy. Die Engine hat ihre eigene Liste vertrauenswürdiger Proxys,
Q.webserver.proxy.trusted in der Konfiguration der Engine, standardmäßig 127.0.0.1 und ::1. Sie ist von
TrustedProxies[] getrennt, weil die Engine entscheidet, bevor irgendein PHP der Anwendung läuft:
- Die Adresse des Besuchers. Von einem vertrauenswürdigen Proxy übernimmt die Engine die Adresse des Besuchers aus
X-Forwarded-For(oder dem inQ.webserver.proxy.headers.ipbenannten Header), von rechts gelesen: Die erste Adresse, die kein vertrauenswürdiger Proxy ist, ist der Besucher. Diese Adresse übergibt sie dem Kernel alsREMOTE_ADDR. Der Kernel sieht den Besucher dann als Gegenstelle:ClientIpByCustomHTTPHeaderist nicht nötig, undTrustedProxies[]beeinflusst die Adresse des Besuchers nicht. - HTTPS. Die Engine setzt
$_SERVER['HTTPS']undREQUEST_SCHEME, denen der Kernel ohne jede Proxy-Einstellung glaubt. Eine TLS-Verbindung zu Velocity selbst ist HTTPS, gleich wer sie gesendet hat. Eine einfache Verbindung gilt als HTTPS, wenn ein vertrauenswürdiger ProxyX-Forwarded-Proto: https(oder den inQ.webserver.proxy.headers.protobenannten Header),CloudFront-Forwarded-Proto: httpsoder dasCF-Visitor: {"scheme":"https"}von Cloudflare sendet; bei einer Liste wiehttps, httpzählt der erste Eintrag. - Engine-Versionen. Das Lesen des weitergeleiteten Protokolls nur von vertrauenswürdigen Proxys kam mit
Exponential Velocity 0.0.4.44 (Engine-Commit
380a64d, 5. Oktober 2026), der Release, die diecomposer.jsonvon Exponential vorschlägt. Bis einschließlich 0.0.4.43 übernahm ein Worker diese Header von jedem Client, sodass ein Besucher an einem einfachen Listener eine Anfrage für die Anwendung wie HTTPS aussehen lassen konnte. Prüfen Sie die installierte Version mitcomposer show se7enxweb/exponential-velocityund aktualisieren Sie mitcomposer require se7enxweb/exponential-velocity:~0.0.4.44. Halten Sie bei einer älteren Engine den einfachen Port von Velocity von außen unerreichbar (das ausgelieferteHost=127.0.0.1oder eine Firewall), wann immer ein Proxy davorsteht. Ab 0.0.4.44 muss ein Proxy, der TLS terminiert, inQ.webserver.proxy.trustedaufgeführt sein, sonst sieht die Website dahinter einfaches HTTP. - Der Host.
X-Forwarded-Hosterreicht den Kernel von der Adresse des Besuchers aus und wird nicht verwendet. Lassen Sie den Proxy den ursprünglichenHost-Header weitergeben.
Um einem Proxy unter einer anderen Adresse zu vertrauen, legen Sie die Liste in einem Snippet des Konfigurationsbaums ab (Abschnitt 8.3.10) und aktivieren es. Nennen Sie auch die Loopback-Adressen, damit ein lokaler Proxy weiter funktioniert:
cat > /etc/vc/conf-available/reverse-proxy.conf <<'EOF'
{ "Q": { "webserver": { "proxy": { "trusted": ["127.0.0.1", "::1", "192.0.2.10", "10.0.0.0/8"] } } } }
EOF
php bin/php/console exp:velocity conf enable --apply reverse-proxy --allow-root-user
php bin/php/console exp:velocity restart --allow-root-userreverse-proxy ist nur ein Name, den Sie wählen; jede Datei in conf-available/ funktioniert auf dieselbe Weise.
Einträge sind Adressen oder CIDR-Bereiche.
nginx vor Velocity (abgeleitetes Beispiel):
location / {
proxy_pass http://127.0.0.1:8088;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
# appending is safe: Exponential reads the list from the right
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
}Apache vor Velocity (abgeleitetes Beispiel):
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8088/
ProxyPassReverse / http://127.0.0.1:8088/
RequestHeader set X-Forwarded-Proto "https"(mod_proxy, mod_proxy_http und mod_headers; mod_proxy von Apache fügt X-Forwarded-For selbst hinzu und hängt
es an einen vom Client gesendeten Wert an, was sicher ist, weil die Liste von rechts gelesen wird.)
Hinweise:
- Let's Encrypt hinter einem Proxy: Der Proxy belegt Port 80; lassen Sie also entweder ihn das Zertifikat beziehen,
oder leiten Sie
/.well-known/acme-challenge/an Velocity weiter, oder setzen Sie dasacme.webrootder Engine auf ein Verzeichnis, das der Proxy ausliefert. - Cachende Proxys dürfen keine Seiten angemeldeter Benutzer speichern. Exponential sendet
privatebei Seiten mit einem Formular-Token; ein Proxy, der nach Tags leert, liest den Header, der inhttpcache.ini [HttpCacheSettings] TagHeaderbenannt ist (standardmäßigdisabled). - Der Antwort-Cache von Velocity funktioniert auch hinter einem Proxy; leeren Sie ihn wie gewohnt mit
exp:velocity cache clear. - Apache oder nginx vor Apache mit PHP-FPM (das nginx von Plesk vor Apache hat diese Form): Wenn der innere Server
REMOTE_ADDRmitmod_remoteipoder demrealip-Modul von nginx auf den Besucher umschreibt und über HTTPS erreicht wird, sieht der Kernel den Besucher undHTTPS=ondirekt und braucht weder Änderungen anTrustedProxies[]nochClientIpByCustomHTTPHeader.
Prüfen Sie es. Ein von einem Besucher gesendeter weitergeleiteter Header darf nichts ändern. Direkt gegen die Website (ohne Proxy):
curl -s -o /dev/null -w '%{redirect_url}\n' -H 'X-Forwarded-Proto: https' http://example.com/user/logout
# expected: http://example.com/ -- an https:// address here means the header was believedÜber den Proxy müssen die absoluten Links und Weiterleitungen einer Seite https:// tragen, und „Ist meine Adresse
aufgeführt?“ (iptest) in der Debug-Leiste zeigt die Adresse, die der Kernel für den Besucher verwendet.
Was hinter einem Proxy schiefgehen kann:
| Symptom | Ursache | Abhilfe |
|---|---|---|
Weiterleitungen und absolute Links führen zu http:// | dem Proxy wird nicht vertraut (nicht Loopback, nicht in TrustedProxies[] bzw. für Velocity nicht in Q.webserver.proxy.trusted), oder er sendet kein X-Forwarded-Proto | ihn aufführen; den Header im Proxy setzen |
| jeder Besucher hat die Adresse des Proxys (Anmeldesperre, Logs) | dem Proxy wird nicht vertraut, oder ClientIpByCustomHTTPHeader ist unter Apache oder nginx mit PHP-FPM nicht gesetzt | den Proxy aufführen; ClientIpByCustomHTTPHeader=X-Forwarded-For setzen |
| eine Weiterleitungsschleife nach dem Umstellen der Website auf HTTPS | der Proxy spricht mit dem Besucher HTTPS, mit dem Server einfaches HTTP, und der Server weiß es nicht | wie in der ersten Zeile |
| Seiten angemeldeter Benutzer werden anderen Besuchern ausgeliefert | ein cachender Proxy speichert Seiten mit einem Sitzungs-Cookie | Antworten nicht cachen, die das Sitzungs-Cookie setzen oder davon abhängen |
8.9 Checkliste
- To do:
Engine=qbixgesetzt,exp:velocity statuszeigt den laufenden Server, die Website antwortet. - To do:
Host,Port,HTTPSPortwie beabsichtigt; Ports 80 und 443 in der Firewall offen, wenn Velocity direkt vor den Besuchern steht. - To do: Die Worker laufen unter dem Benutzer der Website (
Workers as: ...invar/vc/qbix/run/console.log), nie als root. - To do: HTTPS: Ein CA-Zertifikat wird ausgeliefert (
exp:velocity ssl show), nicht der selbstsignierte Ersatz; Erneuerung geplant. - To do:
HSTSMaxAgeerst erhöht, nachdem jeder Name dauerhaft auf HTTPS läuft. - To do: Ein Systemdienst startet Velocity nach einem Neustart des Rechners.
- To do:
[DeploySettings] PhpFpmService=disabled, wenn Velocity die Website allein ausliefert;exp:velocity deploy --dry-runzeigt die erwarteten Schritte. - To do: Apache oder nginx:
.htaccessaus.htaccess_rootkopiert (oder der abgeleitete nginx-Block), Front-Controller und Asset-Pfade getestet, eine.phpunterhalb des Wurzelverzeichnisses antwortet mit 404;./console exp:setup:statusnennt die Vorlage. - To do:
var/undsettings/beschreibbar für den einen Benutzer (oder die eine Gruppe), der PHP ausführt; keine Dateien invar/, die root gehören. - To do: Hinter einem Proxy: Dem Proxy wird vertraut (
TrustedProxies[]bzw. für VelocityQ.webserver.proxy.trusted), er setztX-Forwarded-Protound hängt anX-Forwarded-Foran oder setzt es;ClientIpByCustomHTTPHeadernur unter Apache oder nginx mit PHP-FPM gesetzt; die curl-Prüfung aus Abschnitt 8.8 besteht.
Eine öffentliche Demo. Eine Demo, deren Administratoranmeldung veröffentlicht ist, braucht die Umgebungsvariable EXP_DEMO_MODE=1 im PHP jedes Servers, der sie ausliefert: SetEnv EXP_DEMO_MODE 1 (Apache, LiteSpeed), env[EXP_DEMO_MODE] = 1 (PHP-FPM-Pool), fastcgi_param EXP_DEMO_MODE 1 (nginx) oder die Umgebung der Unit, die Velocity startet. Fertige Dateien: Beispiele für den Demo-Modus; Hintergrund: Demo-Modus.
8.10 Referenzen
In diesem Repository:
- Unterstützte Betriebssysteme: die Betriebssysteme, Webserver und PHP-SAPIs, in Stufen eingeteilt (hier getestet, bekanntermaßen funktionsfähig, voraussichtlich funktionsfähig, derzeit nicht möglich)
- Velocity-Engines: Engines,
deploy,Instances, FrankenPHP, Logs, die Dateien, die jede Engine ausliefert, die/Q/-Ansichten - Velocity: Exponential in einem Webserver mit persistenten Workern betreiben
- Velocity-Verzeichnisstruktur auf der Platte (im Stil von Debians Apache)
- Velocity: HTTPS und Zertifikate
- Velocity-Antwort-Cache, Control Panel, Webserver, Pakete und Binärdateien
- Spezifikationen: Worker-Pool, Engine-Einstellungen, HTTP/2 und Sicherheit, Sicherheitsvoreinstellungen
- Upgrade-Hinweise zur Velocity-Engine, FrankenPHP, Engine-Archiv (phar)
- Anleitung zur Bereitstellung
- Weitergeleiteten Headern wird nur von konfigurierten Proxys vertraut
(
TrustedProxies[], Beispiele für Apache, nginx, Velocity, Load Balancer und CDNs) - Voraussetzungen (PHP-Versionen je Server) und Sicherheitshärtung
- Code:
kernel/classes/expvelocity.php,expvelocitydeploy.php,expvelocityconfiglayout.php,expvelocityfrankenphp.php,kernel/private/classes/commands/velocity.php,lib/ezutils/classes/ezsys.php,lib/ezutils/classes/eztrustedproxy.php; im Engine-Paketsrc/Q/WebServer/Proxy.php(vertrauenswürdige Proxys, weitergeleitetes Protokoll) undsrc/Q/WebServer/RunAs.php(Worker-Benutzer) - Die Einstellungen:
settings/velocity.ini; die Rewrite-Regeln:.htaccess_root,.htaccess_root_static; der PHP-Router der Entwicklungs-Engine:bin/php/velocity-router.php - Die frühere einseitige Anleitung: doc/eng-us/INSTALL.md, Abschnitt 8
Extern:
- Exponential-Velocity-Engine: https://github.com/se7enxweb/exponential-velocity (ihre
docs/https.md,docs/layout.md,docs/workers.md,docs/requirements.md,docs/dashboard.md,docs/panel.md,service/undpackaging/systemd/); die Änderung am weitergeleiteten Protokoll ist Commit 380a64d, veröffentlicht in v0.0.4.44 - Apache HTTP Server: mod_rewrite, mod_proxy_fcgi, mod_ssl, mod_proxy, mod_headers, mod_http2, mod_remoteip, AllowOverride
- nginx: location, try_files, fastcgi-Modul, proxy-Modul, ssl-Modul, realip-Modul, client_max_body_size
- PHP: FastCGI Process Manager (FPM), FPM-Konfiguration, eingebauter Webserver, OPcache
- FrankenPHP: https://frankenphp.dev/ und seine Dokumentation; Caddy: https://caddyserver.com/docs/
- Let's Encrypt: Wie es funktioniert, Challenge-Typen, Staging-Umgebung, Ratenlimits; ACME: RFC 8555
- systemd: systemd.service
- Die Apache-Verzeichnisstruktur von Debian: README.Debian von apache2
- HSTS: RFC 6797, hstspreload.org
Inhalt · Zurück: 7. Die Installation über die Konsole · Weiter: 9. Datenbanken
Werden Sie Exponential-Partner
Partner teilen ihre Informationen, stellen Mittel bereit, geben Beiträge zurück und entwickeln die Produkte mit uns, und so wächst Exponential. Eine Partner-Website und ein Dashboard sind für Mitte 2027 geplant: Werden Sie noch heute Partner, damit wir schneller wachsen und neue Funktionen früher liefern.