Przy okazji zmian na stronie wykorzystałem możliwość uruchomienia sieci witryn. W skrócie polega to na tym, że zamiast stawiać kilka instalacji WordPressa i kolejne strony/blogi uruchamiać na nich niezależnie, tworzymy tylko jedną instalacje, która obsługuje wszystkie strony. Poszczególne strony, choć są całkowicie niezależne, współdzielą kod WordPressa i wtyczek, całość jest więc prostsza w utrzymaniu (aktualizujemy tylko jedną instalację) i wydajniejsza. Oczywiście uruchomienie sieci witryn wymaga więcej zachodu niż proste zainstalowanie WordPressa, skutkuje też kilkoma niespodziankami (np domyślne ograniczenie wielkości dodawanych plików do 1 MB…) oraz… błędami.
Niedługo po instalacji zauważyłem, że próba wyświetlenia nieistniejącego pliku znajdującego się np w katalogu wp-content
zwraca błąd 500 zamiast błędu 404. Niby jedno i drugie to błąd dający podobny efekt – pliku nie udało się wyświetlić. Jednak błąd 500 świadczy, że w międzyczasie stało się coś niedobrego. W pierwszej kolejności podejrzenia padły na nowy hosting, ale test witryny na innym serwerze wypadł podobnie – to nie wina hostingu, tylko mojej strony. Szybki rzut oka na logi dał pierwszy trop:
1 2 |
[Thu Nov 05 23:27:20 2015] [error] [XXX] core.c(3574): [client XXX] AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace. [Thu Nov 05 23:27:20 2015] [error] [XXX] core.c(3574): [client XXX] AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary. Use 'LogLevel debug' to get a backtrace. |
Problemem jest Mod Rewrite i nieprawidłowe reguły w pliku .htaccess
, które tworzą niekończącą się pętlę przekierowań – najwyraźniej coś zepsułem. Ale okazuje się, że to nie ja coś zepsułem, to efekt domyślnej konfiguracji WordPressa. Proponowana przez WordPressa treść pliku .htaccess
dla konfiguracji, w której kolejne witryny uruchamiane są w „wirtualnych” podkatalogach (np http://domena.pl/strona/
), wygląda tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] # add a trailing slash to /wp-admin RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L] RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L] RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L] RewriteRule . index.php [L] |
Problemem są dwie wyróżnione linie, które mają obsługiwać żądania do plików w wirtualnym katalogu strony, np http://rob006.net/en/wp-content/plik.jpg
to w rzeczywistości plik http://rob006.net/wp-content/plik.jpg
, serwer www musi więc zwrócić plik z drugiego adresu pod pierwszym adresem, i to właśnie robią te reguły. I wszystko działa świetnie, dopóki docelowy plik istnieje. Schody zaczynają się gdy pliku nie ma, wtedy reguła się zapętla i w efekcie powstaje błąd 500. Problemem jest znak ?
w wyrażeniu ([_0-9a-zA-Z-]+/)?
, które odpowiada za obsługę wirtualnego katalogu dla strony. Znak ?
oznacza, że element dla poprzedzającej ją reguły może wystąpić, ale nie musi. Oznacza to, że reguła działa także dla adresów bez prefiksu dla wirtualnego podkatalogu, a więc także dla adresu http://rob006.net/wp-content/plik.jpg
. Jeśli nasz plik nie istnieje, reguła próbuje przekierować plik http://rob006.net/wp-content/plik.jpg
na http://rob006.net/wp-content/plik.jpg
(tak, dokładnie ten sam adres), a ponieważ plik nie istnieje serwer znowu szuka reguły dla pliku, znajdując tą samą regułę znowu próbującą przekierować ten sam plik na ten sam adres – mamy nasza pętlę. Rozwiązaniem jest usunięcie znaku ?
z tych dwóch reguł, tak aby nie działały dla adresów bez prefiksu dla wirtualnego katalogu strony.
TL;DR
Prawidłowa konfiguracja pliku .htaccess
wygląda więc tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] # add a trailing slash to /wp-admin RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L] RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] RewriteRule ^([_0-9a-zA-Z-]+/)(wp-(content|admin|includes).*) $2 [L] RewriteRule ^([_0-9a-zA-Z-]+/)(.*\.php)$ $2 [L] RewriteRule . index.php [L] |