Jak obsługiwać wszystkie istniejące pliki statyczne bezpośrednio za pomocą NGINX, ale resztę przez proxy na serwer zaplecza.

89
location / {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

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

    if (!-f $request_filename) {
        proxy_pass http://127.0.0.1:8080; # backend server listening
        break;
        }
    }

Powyższe będzie obsługiwać wszystkie istniejące pliki bezpośrednio przy użyciu Nginx (np. Nginx po prostu wyświetla kod źródłowy PHP), w przeciwnym razie przekieruje żądanie do Apache. Muszę wykluczyć pliki * .php z reguły, aby żądania dotyczące * .php były również przekazywane do Apache i przetwarzane.

Chcę, aby Nginx obsługiwał wszystkie pliki statyczne, a Apache przetwarzał wszystkie dynamiczne rzeczy.

EDYCJA: Istnieje podejście do białej listy, ale nie jest to zbyt eleganckie, Zobacz wszystkie te rozszerzenia, nie chcę tego.

location ~* ^.+.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js)$ {
    access_log off;
    expires 30d;
    }
location / {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
    }

EDYCJA 2: W nowszych wersjach Nginx użyj try_fileszamiast tego http://wiki.nginx.org/HttpCoreModule#try_files

fmalina
źródło
Dla wyjaśnienia: powyższy kod wyświetli plik statyczny, jeśli istnieje na dysku, jeśli plik nie istnieje, żądanie jest przesyłane do Apache. Działa to przez większość czasu, ponieważ wszystkie adresy URL w moich aplikacjach używają mod_rewrite (lub routingu) i tak naprawdę nie istnieją na dysku. Jedynie bezpośredni dostęp do nazwy pliku * .php jest wyjątkiem i musi zostać przeanalizowany przez Apache.
fmalina

Odpowiedzi:

153

Użyj try_files i nazwanego bloku lokalizacji („@apachesite”). Spowoduje to usunięcie niepotrzebnego dopasowania wyrażenia regularnego i zablokowania. Bardziej wydajny.

location / {
    root /path/to/root/of/static/files;
    try_files $uri $uri/ @apachesite;

    expires max;
    access_log off;
}

location @apachesite {
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
}

Aktualizacja: założeniem tej konfiguracji jest to, że nie ma żadnego skryptu php pod /path/to/root/of/static/files. Jest to powszechne w większości nowoczesnych frameworków php. W przypadku, gdy twoje starsze projekty php mają zarówno skrypty php, jak i pliki statyczne zmieszane w tym samym folderze, być może będziesz musiał dodać do białej listy wszystkie typy plików, które chcesz obsługiwać nginx.

Chuan Ma
źródło
Używam Wordpress, więc czy powinienem umieścić folder przesyłania na serwerze Nginx?
Chameron
7
Mój problem z tym rozwiązaniem: nginx nie używa innej lokalizacji (proxy) i próbuje wyświetlić listę katalogów. Więc zgłasza 403, ponieważ lista katalogów nie jest aktywowana. Edycja: OK, jeśli usuniesz, $uri/to działa.
ChristophLSA
1
Spowodowałoby to proxy / przykład na apache, ale pozwoliłoby na pobranie /example.php.
Terence Johnson
1
@TerenceJohnson Umieszczanie plików php w statycznym folderze plików nie jest bezpieczne. Zwróć uwagę, że ustawiłem root /path/to/root/of/*static*/files;. Pliki php należy umieścić w innym folderze, niedostępnym bezpośrednio z Internetu.
Chuan Ma
2
Wiem, że tak powinno być, ale jeśli ktoś stawia Nginx przed którąkolwiek z wielu popularnych, gotowych aplikacji PHP, które mają wszystko w katalogu głównym i polegają na plikach .htaccess, nie powinien kopiować i wklej swoją konfigurację.
Terence Johnson
18

Spróbuj tego:

location / {
    root /path/to/root;
    expires 30d;
    access_log off;
}

location ~* ^.*\.php$ {
    if (!-f $request_filename) {
        return 404;
    }
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
}

Mam nadzieję, że to działa. Wyrażenia regularne mają wyższy priorytet niż zwykłe ciągi, więc wszystkie żądania kończące się na .phppowinny być przekazywane do Apache, jeśli .phpistnieje tylko odpowiedni plik. Reszta będzie traktowana jako pliki statyczne. Aktualny algorytm oceny lokalizacji jest tutaj .

Jasiu
źródło
6

Jeśli używasz mod_rewrite do ukrycia rozszerzenia swoich skryptów lub po prostu lubisz ładne adresy URL kończące się na /, możesz podejść do tego z innej strony. Powiedz nginx, aby wszystko z niestatycznym rozszerzeniem przechodziło do Apache. Na przykład:

location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|html|htm)$
{
    root   /path/to/static-content;
}

location ~* ^!.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|html|htm)$ {
    if (!-f $request_filename) {
        return 404;
    }
    proxy_set_header X-Real-IP  $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080;
}

Znalazłem pierwszą część tego fragmentu pod adresem : http://code.google.com/p/scalr/wiki/NginxStatic

lo_fye
źródło
To działało świetnie, chociaż nadal otrzymuję błędy w przypadku plików zminimalizowanych (np. Site.min.css i main.min.js itp.). Jak mogę je złapać w wyrażeniu regularnym lokalizacji? @lo_fye
Garth