Cara menghapus jalur dengan proxy_pass nginx

77

Saya memiliki aplikasi web yang sedang berjalan di http://example.com/, dan ingin "me-mount" aplikasi lain, di server terpisah http://example.com/en. Server upstream dan proxy_passtampaknya berfungsi, tetapi untuk satu masalah:

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location /en {
    proxy_pass http://luscious;
  }
}

Saat dibuka example.com/en, aplikasi hulu saya kembali 404 not found /en. Ini masuk akal, karena hulu tidak memiliki jalan /en.

Apakah proxy_pathsolusi yang tepat? Haruskah saya menulis ulang "upstream" sehingga ia mendengarkan /ensebagai gantinya, karena root jalan? Atau adakah arahan yang memungkinkan saya untuk menulis ulang jalan yang dilalui untuk hulu?

berkes
sumber

Jawaban:

134

Ini mungkin cara paling efisien untuk melakukan apa yang Anda inginkan, tanpa menggunakan ekspresi reguler apa pun:

location = /en {
    return 302 /en/;
}
location /en/ {
    proxy_pass http://luscious/;  # note the trailing slash here, it matters!
}
cnst
sumber
1
Sejauh yang saya tahu, bagian terakhir masih akan melewati "/ en" sebagai jalur sepanjang ke proxy, bukan?
Berkel
15
@berkes, tidak, tidak akan - garis miring proxy_passadalah apa yang membuat perbedaan. Juga, jawaban ini lebih benar daripada yang Anda ajukan, karena juga memastikan bahwa proxy_redirecttetap default, jadi, Anda masih bisa menggunakan 302et al di backend Anda, dan membuatnya bekerja dengan benar di mana-mana.
cnst
4
Ah, aku melewatkan slash trailing :(
Vanuan
3
AAARGH! TRAILING SLASH!
barrymac
4
3 jam mencari, dan ya ... Itu garis miring. Terima kasih sobat!
Lucas P.
12

Saya ingin membahas jawaban berbasis regex baru yang semakin populer.

location ~ ^/en(/?)(.*)$ {  # OOPS!
  proxy_pass http://luscious/$2$is_args$args;  # OOPS!
}

Solusinya mungkin tampak lebih lucu pada pandangan pertama, tetapi itu salah karena berbagai alasan.

  • Regex di atas akan cocok dengan permintaan uri /enjoy, mengarahkannya ke /joyhulu. Apakah ini benar-benar dimaksudkan?

  • Permintaan untuk /entidak akan menghasilkan arahan ulang, langsung melayani /dari hulu (hampir seolah-olah permintaan /en/dibuat sebagai gantinya, tetapi tidak cukup). Jika Anda menggunakan URI relatif di dalam halaman akar Anda di bagian hulu (jika tidak, mengapa Anda tidak akan memiliki /en/awalan di sana dalam URI bagian hulu?), Misalnya src="style.css"(yang mungkin merujuk pada bahasa tertentu url("menu.png"), misalnya), maka browser akan meminta agar sebagai /style.cssgantinya /en/style.css. (Atau bahkan jika Anda menggunakan URI absolut di mana-mana, bagaimana jika seseorang mereferensikan sumber semi-opsional semi-relatif relatif?) Ups, tiba-tiba situs mungkin tidak berfungsi, tetapi hanya kadang-kadang atau dalam kasus tepi.

  • Sesuai saran saya sebelumnya pada pertanyaan lain yang telah disebutkan oleh jawaban OP sendiri , menggunakan ekspresi reguler mencegah proxy_redirectarahan dari memiliki nilai default default, offsebaliknya menolaknya . Ini berarti bahwa jika upstream menjawab Location: http://127.0.0.1:8080/en/dir/ketika permintaan /en/dirdibuat, maka itulah yang akan dilihat klien, yang jelas tidak akan berfungsi dengan benar. (Yang akan sangat ironis untuk /enpermintaan yang meminta penggunaan regex di tempat pertama, namun implementasi spesifik ini justru menderita masalah lain seperti yang telah disebutkan di atas.) Plus, jika Anda sudah menggunakanupstreamarahan, maka itu mungkin akan menjadi lebih jelek jika Anda hanya mencoba untuk pergi dengan yang khusus, terutama jika Anda mungkin memiliki lebih dari satu server hulu - bagaimana Anda memiliki yang terpisah proxy_redirectuntuk masing-masing? Anda dapat menggunakan ekspresi reguler di dalam proxy_redirect, juga, mungkin bahkan untuk mencocokkan host mana pun, tetapi lalu bagaimana jika Anda memutuskan untuk memberikan pengalihan lintas-domain di masa mendatang?

Untuk mencoba mengatasi beberapa poin di atas dengan satu lokasi berbasis regex, kita bisa melakukan hal berikut (perhatikan bahwa proxy_passkita juga harus membuang referensi ke server dari upstreamdirektif berbasis, untuk membuatnya proxy_redirectlebih mudah):

location ~ ^/en/?((?<=/).*)?$ {
  location = /en { return 302 /en/; }
  proxy_pass http://127.0.0.1:8080/$1$is_args$args;
  proxy_redirect http://127.0.0.1:8080/ /en/;
}

Jadi, jika Anda bertanya kepada saya, solusi asli dengan dua lokasi tingkat atas saudara kandung masih akan menjadi ide yang lebih baik daripada menggali diri Anda ke dalam lubang kelinci dengan pergi rute regex sebagai gantinya.

cnst
sumber
Ini menyebabkan pengecualian:nginx: [emerg] location "/en" is outside location "^/en/?((?<=/).*
Athlan
1
@Athlan, itu karena Anda seharusnya tidak benar-benar menggunakannya di tempat pertama! Jika masih ingin, Anda dapat meletakkan lokasi itu di luar regexp.
cnst
menempatkan lokalisasi = / en di luar berfungsi dengan sangat baik! terima kasih
Sebastian Webber
7

Jadi, saya menemukan jawabannya di stackoverflow :

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location ~ ^/en(/?)(.*) {
    proxy_pass http://luscious/$2;
  }
}

Pada dasarnya: meneruskan regex ke lokasi dan meneruskan backref ke url proxy_pass.

berkes
sumber
Saya pikir "proxy_pass luscious / $ ;" harus "proxy_pass luscious / $ 2 "
Zafer
1
@ Zafer benar, jawaban di atas memberi saya kesalahan
franck
Saya telah mengubah jawabannya, tetapi tidak memiliki server di mana saya dapat mencoba ini, ATM, sehingga tidak diverifikasi.
Berkel
0

Akuntansi ke dokumen Nginx

Untuk meneruskan permintaan ke server proxy HTTP, proxy_pass direktif ditentukan di dalam lokasi. Sebagai contoh:

location /some/path/ {
    proxy_pass http://www.example.com/link/;
}

Contoh konfigurasi ini menghasilkan melewati semua permintaan yang diproses di lokasi ini ke server proksi di alamat yang ditentukan. Alamat ini dapat ditentukan sebagai nama domain atau alamat IP. Alamat tersebut juga dapat mencakup port:

location ~ \.php {
    proxy_pass http://127.0.0.1:8000;
}

Perhatikan bahwa pada contoh pertama di atas, alamat server proksi diikuti oleh URI, / tautan /. Jika URI ditentukan bersama dengan alamat, itu menggantikan bagian dari permintaan URI yang cocok dengan parameter lokasi. Misalnya, di sini permintaan dengan Us /some/path/page.html akan diproksi ke http://www.example.com/link/page.html . Jika alamat tersebut ditentukan tanpa URI, atau tidak mungkin untuk menentukan bagian URI yang akan diganti, URI permintaan penuh diteruskan (mungkin, dimodifikasi).

Jeff
sumber