Bagaimana cara mengatur halaman kesalahan mundur di nginx?

10

Saya mengonfigurasi penanganan nginx terhadap beberapa halaman kesalahan dan file media "default" lainnya (seperti favicon.ico dan robots.txt) saat ini dan saya mengalami masalah kecil membuat semuanya berfungsi seperti yang saya inginkan untuk halaman kesalahan tertentu .

Pada dasarnya, yang saya coba lakukan adalah melayani file-file tertentu untuk server di bawah root untuk server itu, misalnya /var/www/someserver.com/robots.txt. Jika file itu tidak ada, saya ingin nginx untuk pergi ke "default", yaitu /var/www/default/robots.txt. Ini adalah inti dasar dari bagaimana saya mengonfigurasikannya (berhasil):

server {
    ...
    root /var/www/someserver.com;

    location ~* ^/(robots\.txt)$ {
        error_page 404 = @default;
    }

    location @default {
        root /var/www/default;
    }
}

Itu bagus sekali.

Saya mencoba melakukan hal yang sama untuk halaman kesalahan, dan saya tidak dapat mewujudkannya:

server {
    ...
    root /var/www/someserver.com;

    error_page 404   /404.html;

    location ~* ^/(404\.html)$ {
        error_page 404 = @default;
    }

    location @default {
        root /var/www/default;
    }
}

Perhatikan bahwa ini "berfungsi" dalam arti bahwa jika Anda mengunjungi someserver.com/404.html, pertama-tama ia akan mencoba memuat /var/www/someserver.com/404.html dan kemudian kembali ke / var / www / default /404.html jika itu tidak ditemukan. Namun, jika Anda mengunjungi someserver.com/blahblah, itu hanya menampilkan halaman 404 jika diset di /var/www/someserver.com/. Itu tidak kembali ke direktori default jika file itu tidak ada.

Bagaimanapun, Anda mungkin dapat apa yang saya coba capai (itu sebabnya saya memasukkan contoh kerja pertama).

Ada ide?

Edit:

Berdasarkan jawaban Martin F, inilah yang akhirnya saya kumpulkan:

# Doesn't work when error page is returned on a POST request
server {
    ...
    root /var/www/someserver.com;

    error_page  404         = @notfound;
    error_page  500 502 504 = @server_error;
    error_page  503         = @maintenance;

    location @notfound {
        try_files /404.html /../default/404.html =404;
    }

    location @server_error {
        try_files /500.html /../default/500.html =500;
    }

    location @maintenance {
        try_files /503.html /../default/503.html =503;
    }
}

Ini bekerja dengan luar biasa. Blok aktual error_pages dan lokasi di atas ada dalam file server_defaults.conf yang disertakan dengan setiap host virtual, itulah sebabnya saya tidak menyulitkan kode jalur ke setiap lokasi dan menggunakan jalur relatif untuk default.

Edit 2:

Pendekatan ini memiliki masalah. Jika Anda POST ke URL yang mengembalikan kesalahan, metode permintaan POST dikirim dengan upaya try_files. Ini (bagi saya) menghasilkan kesalahan 405 Tidak Diperbolehkan, karena nginx pada dasarnya mencoba POST untuk contoh /default/500.html alih-alih hanya mendapatkan halaman itu.

Edit 3:

Saya memposting solusi yang bekerja yang jauh lebih dekat dengan ide awal saya.

Jim D
sumber

Jawaban:

10

Saya akhirnya pergi dengan sesuatu yang jauh lebih dekat dengan ide awal saya. Kunci yang saya lewatkan ternyata menjadi arahan recursive_error_pages. Yang harus saya lakukan hanyalah menyalakan "nyala" ini dan ide awal saya berhasil. Beginilah bagian yang relevan dari conf saya sekarang:

server {
    ...

    root /var/www/someserver.com/;

    error_page 400 404      /404.html;
    error_page 500 502 504  /500.html;
    error_page 503          /503.html;

    recursive_error_pages   on;

    location ~* ^/(404\.html|500\.html|503\.html)$ {
        log_not_found off;
        error_page 404 = @default;
    }

    location @default {
        log_not_found on;
        root /var/www/default;
    }
}

Saya memasukkan jenis kesalahan lain yang bukan bagian dari pertanyaan awal saya di sini karena inilah yang akhirnya menyebabkan saya kesulitan dengan pendekatan Martin F, yang sebaliknya sangat baik. The log_not_founddirektif hanya memastikan bahwa saya tidak mendapatkan 404 di log saya ketika halaman kesalahan tidak ditemukan di root asli.

Jim D
sumber
Ini berfungsi baik (terutama kombinasi 404 / POST) tetapi tampaknya menelan kode Kesalahan HTTP dan mengirim 200 ... Apakah Anda memiliki perilaku yang sama seperti saya lakukan?
Oktober
2
Anda mungkin ingin menghapus log_not_found off;dan menambahkan internal;.
Alix Axel
Masalah yang Anda perhatikan dengan permintaan POST yang mengakibatkan kesalahan adalah perilaku aneh oleh nginx, lihat trac.nginx.org/nginx/ticket/824
Robo
5

try_files adalah cara untuk pergi ke sini. Konfigurasi berikut seharusnya berfungsi, tetapi saya belum mengujinya untuk kesalahan sintaksis.

server {
    ...
    root /var/www;

    location / {
        try_files /someserver.com$uri /default$uri /someserver.com$uri/ /default$uri/ @notfound;
    }

    location @notfound {
       try_files /someserver/404.html /default/404.html =404; # =404 should make it use the nginx-default 404 page.
    }
}
Martin Fjordvald
sumber
Ya, itulah yang saya butuhkan. Saya telah mencoba menggunakan try_files tetapi jawaban Anda membuat saya menyadari bahwa saya perlu membuat lokasi internal khusus untuk itu. Saya telah mengedit jawaban saya untuk menunjukkan konfigurasi yang berfungsi untuk saya, yang memiliki beberapa penyesuaian terhadap apa yang Anda sarankan.
Jim D
Lihat hasil edit saya 2 di atas. Dari apa yang saya tahu, saran ini tidak berfungsi dengan permintaan POST. Karena try_files menggunakan metode permintaan dari permintaan asli, Anda berakhir dengan respons 405 Tidak Diizinkan.
Jim D
@ JimD: Yah Anda tidak benar-benar menggunakan pendekatan ini, Anda menggunakan yang dimodifikasi. Ini bekerja untuk saya. Coba tingkatkan biner Nginx Anda jika lebih tua dari 0,8.x
Martin Fjordvald
Masalahnya adalah saya menggunakan ini lebih dari 404-an saja, itulah sebabnya saya harus melakukan error_page -> location -> try_files alih-alih lokasi -> try_files -> location -> try_files seperti Anda. Namun saya menggunakan binari 0.7.x dari sebuah paket, jadi saya akan mencoba membangunnya dari sumber dan melihat apakah itu menyelesaikannya.
Jim D
2

Sayangnya saya terlambat beberapa tahun dengan jawaban saya, tetapi saya pikir itu mungkin membantu pencari masa depan. Versi Nginx saya yang terinstal adalah 1.2.4, dan saya telah membuat snippet konfigurasi berikut,

server {

server_name www.example.com
root /var/www/example


## Errors -> Locations
error_page   400 /400.html;
error_page   403 /403.html;
error_page   404 /404.html;
error_page   500 502 503 504 /50x.html;

## Locations -> Fallback
location = /400.html {
    try_files /400.html @error;
    internal;
}
location = /403.html {
    try_files /403.html @error;
    internal;
}
location = /404.html {
    try_files /404.html @error;
    internal;
}
location = /50x.html {
    try_files /50x.html @error;
    internal;
}

## Fallback Directory
location @error {
    root /var/www/error;
}

}
JM Becker
sumber
1
Baik digunakan internal.
Clint Pachl