Tesztkörnyezetet alakítottam ki két Apache VirtualHost-tal, amihez két külön PHP-FPM pool tartozik. Mindkét pool külön user-re van chroot-olva.
Az egyik VirtualHost a domain.tld és aliasként a www.domain.tld kérelmeket szolgálja ki az egyik php pool-al.
A másik VirtualHost az aldomain.domain.tld kérelmeket szolgálja ki a másik php pool-lal.
Amennyiben egy kérelem úgy érkezik be az aldomain.domain.tld alá, hogy közben ugyanarra a php fájlra a domain.tld alá is érkezett kérelem, úgy az aldomain-ra érkező kérelmet a domain alatt lévő php kezdi el kiszolgálni. Vagyis:
Ha a http://domain.tld/index.php és http://aldomain.domain.tld/index.php kérelmek egyszerre érkeznek be az Apache-hoz, úgy a http://aldomain.domain.tld/index.php kérelem kiszolgálását a domain.tld/index.php kezdi el, de időközben átveszi azt az aldomain.domain.tld pool-ja, és természetesen hibát dob. Ha a kérelem kiszolgálása gyorsabban befejeződik, mint ahogy átvenné akkor hiba nélkül befejeződik a kérelem kiszolgálása.
A két pool két külön user-re van chroot-olva, tehát még véletlenül sem lenne szabad egymás tárterületeit elérniük. Azonban az aldomain.domain.tld alatti php hibanaplóban megjelenik a hibaüzenet, ami egy domain.tld alatti php fájlban jelez hibát, amint egy másik, domain.tld alatti php-t próbál include paranccsal behívni. A hiba szerint az include-ban szereplő fájl nem elérhető. De az a php fájl, amiben ez a hibás include van, maga is egy include-dal került végrehajtásra, és arra még nem jelzett hibát, pedig mindkét fájl a chroot-on kívüli másik user fájlrendszerében érhető csak el.
A keveredés csak akkor fordul elő, ha az aldomain.domain.tld/index.php kérelem egyszerre kerül kiszolgálásra a domain.tld/index.php kérelemmel.
A keveredés akkor is előfordul, ha a domain.tld/index.php fájl csak egy "print time();" parancsot tartalmaz, és még session-t sem indít (az auto_session is off). Ez esetben hibaüzenet ugyan nem keletkezik, mivel túl gyorsan befejeződik a kérelem kiszolgálása, de az aldomain.domain.tld/index.php kérelemre megjelenik az időbélyeg, pedig a print time() parancs csak a másik user tárterületén tárolt index.php fájlban van.
A hiba előfordulását nem befolyásolja, hogy az url-ben szerepel-e az index.php vagy a defaultIndex miatt indul el. A lényeg, hogy mindkét VirtualHost-on belül ugyanolyan nevű php szolgálja ki a kérelmet. Akkor is jelentkezik, ha mindkettő az index2.php-ra vonatkozik.
A két VirtualHost ServerName és ServerAlias értékei csak konkrét domainnevek, és nincs átfedés közöttük, kivéve, hogy minden aldomain a domain.tld aldomainje. Emiatt azt várnám, hogy a PHP pool-ok már az Apache szintjén elkülönülnek, ami általában igaz is, kivéve, ha egyszerre érkeznek be a kérelmek.
A hiba nem fordul elő, ha
a két kérelem mindegyike aldomain, azaz a domain.tld helyett a www.domain.tld-re érkezik a párhuzamos kérelem.Sajnos sikerült közben ilyen esetben is reprodukálnom a jelenséget.- akkor sem fordul elő, ha a két egyszerre beérkező kérelem nem ugyanarra a php-ra vontkozik, vagyis az egyik mondjuk index.php-ra, a másik index2.php-ra.
Erre varrjatok gombot.
Ha valakinek van ötletet, hogy kerülhető meg ez a hiba, vagy hogyan lehet úgy konfigurálni akár az Apache, akár a PHP-FMP rendszert, hogy még ebben a speciális esetben se keveredhessenek össze a kérelmek, kérem ossza meg velem.
Megoldás:
opcache.validate_root = 1
- 537 megtekintés
Hozzászólások
Rég használtam PHP-FPM-et, de nem mutat a két VirtualHost véletlenül ugyanarra az FPM-re?
- A hozzászóláshoz be kell jelentkezni
Ha ugyanarra az FPM-re mutatna, akkor minden esetben ugyanaz szolgálná ki, nem csak akkor, amikor egyszerre érkeznek be a kérelmek.
- A hozzászóláshoz be kell jelentkezni
latni kellene a vhost beallitasokat es az fpm configokat
- A hozzászóláshoz be kell jelentkezni
Kérdés, hogy az FPM opciók kellenek-e egyáltalán? Hisz az apache-nak már biztosítania kellene, az elkülönítést, amit jól is csinál, kivéve, ha egyszerre érkeznek be a kérelmek. Ha az FPM lenne rosszul konfigurálva, akkor minden kérelemnél hibás lenne.
Az Apache konfig fontos részei:
<VirtualHost *:80>
ServerName domain.tld
ServerAlias www.domain.tld
DocumentRoot "/home/domain.tld/public"
SetEnv document_root "/public"
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
<FilesMatch "\.php$">
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:unix:/run/php/domain.tld-8.2.sock|fcgi://localhost"
</If>
</FilesMatch>
<Directory /home/domain.tld/public>
Require all granted
</Directory>
CustomLog /home/domain.tld/log/domain.tld-access.log combined
ErrorLog /home/domain.tld/log/domain.tld-error.log
</VirtualHost>Az aldomain.domain.tld is analog:
<VirtualHost *:80>
ServerName aldomain.domain.tld
ServerAlias aldomain2.domain.tld
DocumentRoot "/home/aldomain.domain.tld/public"
SetEnv document_root "/public"
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
<FilesMatch "\.php$">
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:unix:/run/php/aldomain.domain.tld-8.2.sock|fcgi://localhost"
</If>
</FilesMatch>
<Directory /home/aldomain.domain.tld/public>
Require all granted
</Directory>
CustomLog /home/aldomain.domain.tld/log/domain.tld-access.log combined
ErrorLog /home/aldomain.domain.tld/log/domain.tld-error.log
</VirtualHost>A két user a domain.tld és az aldomain.tld.
- A hozzászóláshoz be kell jelentkezni
Csúf megoláds, de működhet: a domain.tld-t ne szolgáld ki, helyette legyen egy redirect a www.domain.tld-re. Innen kezdve működik a dolog: azt írtad, hogy aldomainek kiszolgálása esetén a probléma nem áll fenn.
Tudom, a hiba oka is érdekelne - azt sajnos nem tudom, de engem is érdekelne.
- A hozzászóláshoz be kell jelentkezni
Sajnos közben sikerült reprodukálnom a jelenséget úgy, hogy a www.domain.tld volt a párhuzamos kérelem, vagyis két aldomain esetén is összeakadat.
- A hozzászóláshoz be kell jelentkezni
opcache.validate_root = 1
?
- A hozzászóláshoz be kell jelentkezni
Nagyon tudsz!
Nem akarom elkiabálni, de mióta beállítottam, nem sikerült reprodukálnom. Még tesztelem, és csak akkor lesz megoldott a szál, ha tartósan tényleg jó, de egyelőre jónak tűnik! Köszönöm!
- A hozzászóláshoz be kell jelentkezni
igen, ez lesz az
- A hozzászóláshoz be kell jelentkezni
[dupe]
- A hozzászóláshoz be kell jelentkezni
Úgy néz ki, tényleg ez volt a megoldás, azóta sem jelentkezett a hiba. Még egyszer köszönöm!
- A hozzászóláshoz be kell jelentkezni
az is megoldas, ha kikapcsolod az opcache-t :)
neked aztan fura humorod van...
- A hozzászóláshoz be kell jelentkezni
https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.validate-root
eloszor nem hittem a szememnek, le is fordittattam a translate-el is.
"Megakadályozza a névütközéseket chrootolt környezetekben. Ezt minden chrootolt környezetben engedélyezni kell, hogy megakadályozza a chrooton kívüli fájlokhoz való hozzáférést."
a chroot mire valo? :)
neked aztan fura humorod van...
- A hozzászóláshoz be kell jelentkezni
Az opcache ezen felül még egy csomó további csodára képes. :)
Jelen esetben, lásd az előzményeket: https://bugs.php.net/bug.php?id=69090
- A hozzászóláshoz be kell jelentkezni
:) igen, ez tenyleg csoda hogy mukodik.
en csak arra reagaltam, hogy a parameter beallitasa kell ahhoz, hogy "megakadályozza a chrooton kívüli fájlokhoz való hozzáférést". ertem en, hogy cache-eli es igy a masik chroot-bol szarmazo fajlt hasznalja, mert chroot-on belul ugyanaz az utvonal, de nem a fajlhoz fer hozza, hanem a cache-elt fajlhoz, ami persze ugyanugy problema.
amugy nincs valami azonosito, amit az utvonal ele lehetne biggyeszteni, mielot hash-eli az utvonalat? mondjuk a socket inode-jat, amin kommunikal.
pl. a /var/lib/php8.2-fpm/web1.sock es web2.sock inode-ja, ezek nem lesznek ugyanazok:
hash('1000:/app.php')
hash('1001:/app.php')
neked aztan fura humorod van...
- A hozzászóláshoz be kell jelentkezni
Az opcache engem is megszívatott tegnap, látom mást is szokott. Oda kell rá figyelni ha használjuk!
- A hozzászóláshoz be kell jelentkezni