Problemy z wieloma lokalizacjami Nginx

15

Obecnie próbuję rozdzielić 3 aplikacje z jednego repozytorium na 3, ale zachowując strukturę adresu URL, więc zasadniczo różne lokalizacje w tej samej domenie muszą być dostarczane przez różne aplikacje.

Mam problem z tym, że jedna z aplikacji musi być rezerwą dla nieistniejących adresów URL, więc jeśli pierwsza nie pasuje, a druga nie, to trzecia powinna obsłużyć żądanie

Struktura, którą mam to:

/ etc / nginx / sites-enabled / main_site, tutaj oprócz nazwy serwera i dzienników include /etc/nginx/subsites-enabled/*, w których mam 3 pliki konfiguracyjne, po jednym dla każdej aplikacji.

Każdy z 3 plików konfiguracyjnych zawiera blok lokalizacji.

Próbowałem negatywnego lookahead w wyrażeniu regularnym (w zasadzie próbuję zakodować adresy URL obsługiwane przez inne aplikacje), ale nie powiodło się.

Podsumowując:

/ i / community powinno być dostarczone przez /etc/nginx/subsites-enabled/example.org/home (kilka skryptów perla)

/ news powinien być dostarczony przez /etc/nginx/subsites-enabled/example.org/news (wordpress)

wszystko inne powinno być dostarczone przez /etc/nginx/subsites-enabled/example.org/app (aplikacja do ciastek)

Bit Perla działa dobrze. Problem, który mam, polega na tym, że aplikacja przejmuje wiadomości (prawdopodobnie dlatego, że pasuje. *), Próbowałem różnych opcji (byłem przy tym przez 2 dni), ale żadna z nich nie rozwiązała wszystkich problemów (czasami zasoby statyczne nie działałyby itp.).

Moja konfiguracja to:

/etc/nginx/sites-enabled/example.org:

server {
    listen   80;
    server_name example.org;
    error_log /var/log/nginx/example.org.log;

    include /etc/nginx/subsites-enabled/example.org/*;
}

/etc/nginx/subsites-enabled/example.org/home:

location = / {
  rewrite ^.*$ /index.pl last;
}

location ~* /community(.*) {
  rewrite ^.*$ /index.pl last;
}

location ~ \.pl {
  root   /var/www/vhosts/home;
  access_log /var/log/nginx/home/access.log;
  error_log /var/log/nginx/home/error.log;

  include /etc/nginx/fastcgi_params;
  fastcgi_index index.pl;
  fastcgi_param SCRIPT_FILENAME /var/www/vhosts/home$fastcgi_script_name;
  fastcgi_pass  unix:/var/run/fcgiwrap.socket;
}

/ etc / ngins / subsites-enabled / news

location /news {
  access_log /var/log/nginx/news/access.log;
  error_log /var/log/nginx/news/error.log debug;

  error_page 404 = /news/index.php;

  root /var/www/vhosts/news;

  index index.php;

  if (!-e $request_filename) {
      rewrite ^.*$ /index.php last;
  }

  location ~ \.php {
    include /etc/nginx/fastcgi_params;
    fastcgi_pass  127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /var/www/vhosts/news$fastcgi_script_name;
  }
}

/ etc / nginx / subsites-enabled / app:

location ~ .* {
  access_log /var/log/nginx/app/access.log;
  error_log /var/log/nginx/app/error.log;

  rewrite_log on;

  index index.php;
  root /var/www/vhosts/app/app/webroot;

  if (-f $request_filename) {
    expires 30d;
    break;
  }

  if (!-e $request_filename) {
    rewrite ^.*$ /index.php last;
  }

  location ~ \.php {
    include /etc/nginx/fastcgi_params;
    fastcgi_pass  127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /var/www/vhosts/app/app/webroot$fastcgi_script_name;
  }
}
Andrei Serdeliuc
źródło
a) opublikuj swoją konfigurację wraz z kilkoma przykładami, gdzie powinny iść różne przekierowania (w tym te dla nieistniejących adresów URL). b) użyj try_files z nazwanym blokiem lokalizacji (używając @prefiksu), który mapuje na twoją domyślną aplikację. Możesz także skonfigurować stronę_błędu, która odwzorowuje 404 na nazwaną lokalizację.
cyberx86,
@ cyberx86 Dodałem więcej szczegółów i moją konfigurację
Andrei Serdeliuc
Szybki rzut oka sugeruje kilka rzeczy: a) dopasowanie wyrażenia regularnego ma pierwszeństwo przed konwencjonalnymi ciągami - aby blok aplikacji pasował zamiast bloku wiadomości - spróbuj location ^~ /news. b) w przypadku bloku aplikacji powinieneś być w stanie to zrobić location /(to nie to samo location = /, ale powinieneś dopasować wszystko, co jeszcze nie jest dopasowane. c) w niektórych przypadkach (szczególnie wyrażenia regularne), kolejność ma znaczenie - możesz połączyć 3 pliki do jednego pliku z blokami we właściwej kolejności. Zamiast tego użyj try_files !-e. Na koniec zobacz wiki.nginx.org/HttpCoreModule#location .
cyberx86,
Próbowałem prawie każdej odmiany tych, w tym łącząc je w jeden plik (chociaż muszą być one oddzielne, ponieważ są wdrażane osobno), żadna z nich nie działa. Aplikacja obsługuje tylko wiadomości.
Andrei Serdeliuc
Cóż, myślę, że to rozwiązałem - nieco trudniejsze, niż początkowo się spodziewałem - ale z pewnością przyjemne w walce z rozumem. Dzięki za układankę.
cyberx86

Odpowiedzi:

47

W twojej konfiguracji jest kilka błędów, z których dwie są istotne:

  1. Ścieżki w bloku lokalizacji nadal zawierają dopasowaną ścieżkę.
  2. Przepisz z „ostatnią” kontynuuj, przeglądając wszystkie dostępne lokalizacje dla meczu (wybijają się z bieżącego bloku lokalizacji).

Weźmy na przykład adres URL example.org/news/test.htm

  • location /newsBlok będzie go dopasować
  • Stosowana jest wtedy ścieżka /news/test.htm- to się nie zmienia, tylko dlatego, że znajduje się w bloku lokalizacji
  • Dodając ścieżkę do katalogu katalog_główny, otrzymujesz: /var/www/vhosts/news/news/test.htm
  • Twoje if (!-e $request_filename)oświadczenie powinno przechwycić ten nieistniejący plik
  • Przepisz ścieżkę do /index.php
  • Ponieważ używasz, lastprocesy zaczynają się od nowa (wyrwanie z bloku lokalizacji)
  • /index.phpjest teraz przechwytywany przez location /app block.

Wspomniany wyżej problem związany z dyrektywą root jest złożony, gdy wchodzisz do bloku lokalizacji aplikacji. W przeciwieństwie do bloku „news”, w którym można po prostu usunąć „news” ze ścieżki (ponieważ zostanie dodany ponownie), nie można tego zrobić dla ścieżki aplikacji, która kończy się na „webroot”.

Rozwiązanie leży w aliasdyrektywie. Nie zmienia to katalogu_głównego dokumentu, ale zmienia ścieżkę pliku używaną do obsługi żądania. Niestety rewritei try_fileszachowują się nieco nieoczekiwanie alias.

Zacznijmy od prostego przykładu - bez PHP - tylko HTML i blok Perla - ale ze strukturą folderów pasującą do twojej (testowane na Nginx 1.0.12, CentOS 6):

server {
    server_name example.org;
    error_log /var/log/nginx/example.org.error.log notice;
    access_log /var/log/nginx/example.org.access.log;
    rewrite_log on;

    location = / {
        rewrite ^ /index.pl last;
    }

    location ^~ /community {
        rewrite ^ /index.pl last;
    }

    location ~ \.pl {
        root   /var/www/vhosts/home;

        [fastcgi_stuff...]
    }


    location ^~ /news {
        alias /var/www/vhosts/news;
        index index.htm;

        try_files $uri $uri/ /news/index.htm;
    }

    location ^~ /app {
        alias /var/www/vhosts/app/app/webroot;
        index index.htm;

        try_files $uri $uri/ /app/index.htm;
    }

    location / {
        rewrite ^/(.*) /app/$1 last;
    }
}
  • location = / - dopasuje tylko ścieżkę katalogu głównego
  • location ^~ /community - dopasuje każdą ścieżkę zaczynającą się od / community
  • location ~ \.pl - dopasuje wszystkie pliki zawierające .pl
  • location ^~ /news - dopasuje każdą ścieżkę zaczynającą się od / news
  • location ^~ /app - dopasuje każdą ścieżkę zaczynającą się od / app
  • location / - dopasuje wszystkie ścieżki niepasujące powyżej

Powinieneś być w stanie usunąć ^~- ale może zaoferować niewielką poprawę wydajności, ponieważ przestaje szukać po znalezieniu dopasowania.

Chociaż ponowne dodanie bloków PHP powinno być prostą sprawą, istnieje niestety niewielka trudność - try_files(i przepisanie) nie kończy się przekazywaniem pożądanej ścieżki do zagnieżdżonego bloku lokalizacji - i używanie, aliasgdy tylko rozszerzenie jest określone w bloku lokalizacji nie działa.

Jednym z rozwiązań jest użycie oddzielnych bloków lokalizacji, które wykonują przechwytywanie razem z dyrektywą aliasu - nie jest to dość eleganckie, ale o ile wiem, działa (ponownie przetestowane na Nginx 1.0.12, CentOS 6 - z oczywiście nie skonfigurowałem CakePHP, Wordpress i Perla - po prostu użyłem kilku plików PHP i HTML w każdym folderze)

server {
    server_name example.org;
    error_log /var/log/nginx/example.org.error.log notice;
    access_log /var/log/nginx/example.org.access.log;
    rewrite_log on;

    location = / {
        rewrite ^ /index.pl last;
    }

    location ^~ /community {
        rewrite ^ /index.pl last;
    }

    location ~ \.pl {
        root   /var/www/vhosts/home;
        access_log /var/log/nginx/home.access.log;
        error_log /var/log/nginx/home.error.log;
        include /etc/nginx/fastcgi_params;
        fastcgi_index index.pl;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass  unix:/var/run/fcgiwrap.socket;
    }

    location /news {
        access_log /var/log/nginx/news.access.log;
        error_log /var/log/nginx/news.error.log notice;
        alias /var/www/vhosts/news;
        index index.php;
        try_files $uri $uri/ /news/index.php;
    }

    location ~* ^/news/(.*\.php)$ {
        access_log /var/log/nginx/news.php.access.log;
        error_log /var/log/nginx/news.php.error.log notice;
        alias /var/www/vhosts/news/$1;
        try_files "" /news/index.php;
        include /etc/nginx/fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_NAME $1;
        fastcgi_param SCRIPT_FILENAME /var/www/vhosts/news/$1;
        fastcgi_pass  127.0.0.1:9000;
    }

    location /app {
        alias /var/www/vhosts/app/app/webroot;
        access_log /var/log/nginx/app.access.log;
        error_log /var/log/nginx/app.error.log notice;
        index index.php;
        try_files $uri $uri/ /app/index.php;
    }

    location ~* ^/app/(.*\.php)$ {
        access_log /var/log/nginx/news.access.log;
        error_log /var/log/nginx/news.error.log notice;
        alias /var/www/vhosts/app/app/webroot/$1;
        try_files "" /app/index.php;
        include /etc/nginx/fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_NAME $1;
        fastcgi_param SCRIPT_FILENAME /var/www/vhosts/app/app/webroot/$1;
        fastcgi_pass  127.0.0.1:9000;
    }

    location / {
        rewrite ^/(.*) /app/$1 last;
    }
}

Powyższa konfiguracja bierze powyższą prostą i wprowadza dwie zmiany:

  • Dodaj dwa bloki lokalizacji:
    • location ~* ^/news/(.*\.php)$ - dopasuje wszystkie pliki z rozszerzeniem .php, a ścieżki zaczynają się od / news /
    • location ~* ^/app/(.*\.php)$ - dopasuje wszystkie pliki z rozszerzeniem .php, a ścieżki zaczynają się od / app /
  • Usuń ^~dopasowanie - jest to wymagane, aby dwa dodane bloki lokalizacji mogły się zgadzać ze ścieżkami (w przeciwnym razie dopasowanie zatrzymałoby się w blokach / news lub / app).

Należy zauważyć, że kolejność dopasowywania lokalizacji jest tutaj bardzo ważna:

  • Najpierw dokładne dopasowania (za pomocą =)
  • Dopasowuje się do ^~drugiego
  • Dopasowywanie bloków wyrażeń regularnych
  • Konwencjonalne ciągi - tylko jeśli nie znaleziono pasującego wyrażenia regularnego

Pasujące wyrażenie regularne zastąpi prosty ciąg!

Ważną rzeczą do wspomnienia jest to, że gdy przechwytywanie jest używane z aliasem, cały adres URL jest zastępowany - nie tylko folder wiodący. Niestety oznacza to, że $fastcgi_script_namepozostało puste - więc użyłem $1powyżej.

Jestem pewien, że będziesz musiał wprowadzić kilka zmian, ale podstawowa przesłanka powinna być funkcjonalna. W razie potrzeby powinieneś być w stanie rozdzielić bloki na wiele plików - kolejność nie powinna wpływać na konfigurację.

cyberx86
źródło
2
Koleś, chciałbym móc cię głosować 100 razy. Jesteś niesamowity. Dzięki!
Andrei Serdeliuc