Nginx proxy ngược + viết lại URL


149

Nginx đang chạy trên cổng 80 và tôi đang sử dụng nó để đảo ngược URL proxy với đường dẫn /foođến cổng 3200theo cách này:

location /foo {
                proxy_pass http://localhost:3200;
                proxy_redirect     off;
                proxy_set_header   Host $host;
}

Điều này hoạt động tốt, nhưng tôi có một ứng dụng trên cổng 3200mà tôi không muốn /foogửi thư đầu tiên . Đó là - khi tôi truy cập http://localhost/foo/bar, tôi chỉ muốn /barlà đường dẫn mà ứng dụng nhận được. Vì vậy, tôi đã thử thêm dòng này vào khối vị trí ở trên:

rewrite ^(.*)foo(.*)$ http://localhost:3200/$2 permanent;

Điều này gây ra chuyển hướng 302 (thay đổi trong URL), nhưng tôi muốn 301. Tôi nên làm gì?


Nếu bạn có bất kỳ vấn đề nào với trường hợp Grafana, bạn nên sử dụng các công thức sau: docs.grafana.org/installation/behind_proxy/ mẹo
mohsen saeedi

Câu trả lời:


168

Mọi chuyển hướng đến localhost đều không có ý nghĩa từ một hệ thống từ xa (ví dụ: trình duyệt Web của máy khách). Vì vậy, các cờ viết lại vĩnh viễn (301) hoặc chuyển hướng (302) không thể sử dụng được trong trường hợp của bạn.

Vui lòng thử thiết lập sau bằng cách sử dụng quy tắc viết lại trong suốt:

location  /foo {
  rewrite /foo/(.*) /$1  break;
  proxy_pass         http://localhost:3200;
  proxy_redirect     off;
  proxy_set_header   Host $host;
}

Sử dụng curl -iđể kiểm tra viết lại của bạn. Một thay đổi rất tinh tế đối với quy tắc có thể khiến nginx thực hiện chuyển hướng.


1
Đường dẫn URL vẫn bắt đầu bằng / foo trong ứng dụng của tôi khi tôi làm điều đó ...
jeffreyveon

Phải có một vấn đề khác. Tôi đã tái tạo kịch bản này thành công, chỉ vài phút trước. URL gốc: http: // Development / foo / testme / 1234 - REQUEST_URI của tập lệnh PHP chạy trên Apache được kết nối dưới dạng proxy back-end: '/ testme / 1234'
Jens Bradler

9
Regex có lẽ nên được /foo(.*), nếu example.com/fookhông sẽ không được khớp. (đó có lẽ là những gì jeffreyveon đã trải qua)
Benno

Đây là loại công việc, nhưng cơ thể tôi đang cài đặt với proxy_set_body đang bị xóa.
Justin Thomas

viết lại /(.*) /socket.io/ break; TIẾT KIỆM NGÀY CỦA TÔI CHO SOCKET.IO
user956584

123

Kết hợp tiền tố vị trí đơn giản hoạt động cho việc này mà không cần sử dụng quy tắc viết lại miễn là bạn chỉ định URI trong lệnh proxy_pass:

location /foo {
  proxy_pass http://localhost:3200/;
}

Lưu ý bổ sung /vào cuối proxy_passchỉ thị. NGINX sẽ loại bỏ tiền tố phù hợp /foovà chuyển phần còn lại vào máy chủ phụ trợ tại URI /. Do đó, http://myserver:80/foo/barsẽ đăng lên phụ trợ tại http://localhost:3200/bar.

Từ các tài liệu NGINX trên proxy_pass :

Nếu chỉ thị proxy_pass được chỉ định bằng URI, thì khi yêu cầu được chuyển đến máy chủ, một phần của URI yêu cầu được chuẩn hóa khớp với vị trí được thay thế bằng URI được chỉ định trong lệnh:


12
Hoạt động với tôi hơn tôi đã thêm / vào vị trí / foo / {
Andrei N

Đây chính xác là những gì tôi đang tìm kiếm!
anbiniyar

6
Đây là một giải pháp rất sạch sẽ, tôi muốn đây là câu trả lời chính tắc cho câu hỏi.
ralien

2
Mất quá nhiều thời gian để nhận ra tầm quan trọng của việc giữ hoặc xóa dấu gạch chéo.
Parvez

5
Điều này thực sự sẽ vượt qua //xyzmáy chủ nếu bạn làm điều đó.
Archimedes Trajano

60

Cách tuyệt đối chính xác nhất và thực hành tốt nhất thường như sau:

location /foo/ {
    proxy_pass http://localhost:3200/; # note the trailing slash!
}

  • Lưu ý tầm quan trọng khủng khiếp của dấu gạch chéo trongproxy_pass , tự động thay đổi $uribiến để có /foo/mặt trước tương ứng với /trên phụ trợ. Không cần một rewritechỉ thị rõ ràng .

  • Ngoài ra, lưu ý rằng dấu vết /tronglocation cũng khá quan trọng - nếu không có nó, bạn có nguy cơ có các URL trông lạ trên trang web của mình tại một thời điểm (ví dụ: hoạt động /fooenbổ sung /foo/en).

    Ngoài ra, dấu /trong locationvới proxy_passcũng đảm bảo một số xử lý đặc biệt , theo tài liệu của các locationchỉ thị, gây ra hiệu quả một tiềm ẩn location = /foo {return 301 /foo/;}là tốt.

    Vì vậy, bằng cách xác định locationdấu gạch chéo như trên, bạn không chỉ đảm bảo rằng các URL hậu tố không có dấu gạch chéo như /fooensẽ không hợp lệ, mà còn /foomột dấu gạch chéo không có dấu sẽ tiếp tục hoạt động tốt.


Tài liệu tham khảo:


Có vẻ như $argsbị mất: http://frontend/foo?bar=bazsẽ được ủy nhiệm http://backend/. Lưu ý rằng args không phải là một phần của url
Vanuan

@Vanuan, bạn có chắc về điều đó? Tôi khá chắc chắn $argsvẫn nên được xử lý một cách thích hợp nếu bạn sử dụng mã ở trên, vì chúng tách biệt $urivà sẽ được tập hợp lại, trừ khi bạn sử dụng các biến rõ ràng trong proxy_pass.
cnst

@cnst ơi, tôi hiểu rồi. Tôi đang sử dụng biến chủ. Đó là phản trực giác.
Vanuan

1
@ArchimedesTrajano, bạn không chính xác, vì có cách xử lý đặc biệt /foođể chuyển hướng đến /foo/, vì vậy, trừ khi bạn làm điều gì đó kỳ lạ trên phần phụ trợ, thậm chí /foocác yêu cầu vẫn sẽ hoạt động với đoạn mã trên. (Đây thực sự đã là một phần của câu trả lời, BTW.)
cnst

3
Mặc dù giải pháp này "dường như" chiến thắng trên tất cả các diễn đàn này, nhưng cần lưu ý trong chính câu trả lời rằng Nginx sẽ giải mã URL và chuyển URL được giải mã đến máy chủ được ủy quyền. Vì vậy, giải pháp này sẽ không hoạt động nếu URL của bạn mang các phần được mã hóa URL.
mã hóa

1

thử

location /foo {
    proxy_pass http://localhost:3200/;
    ....

hoặc là

location ^~ /foo {
    proxy_pass http://localhost:3200/;
    ....

13
Câu trả lời này sẽ tốt nếu bạn đưa ra một số lời giải thích tại sao nó phải được cấu hình như trên.
masegaloeh

Điều này thực sự sẽ vượt qua //xyzmáy chủ nếu bạn làm điều đó.
Archimedes Trajano

1

@Terabuck Xin lỗi vì chưa trả lời chưa có đại diện.

Bạn không nên sử dụng localhost vì bạn phụ thuộc vào thực tế là ứng dụng đang chạy trên máy chủ có tệp lưu trữ. máy chủ lưu trữ cục bộ chỉ là bản dịch mặc định thành 127.0.0.1. Không có gì nói rằng bạn phải có tệp lưu trữ này. Nó chỉ là rất phổ biến để có một.

Có một giao diện loopback lại là một điều phổ biến khác để phụ thuộc nhưng bạn vẫn phụ thuộc vào giao diện loopback trên ngăn xếp mạng. Đó là một trường hợp hiếm hoi để không có hai. Nếu bạn từng lo lắng về điều này. Ít nhất trên unix / linux bạn có tùy chọn cho socket. Điều này sẽ loại bỏ sự cần thiết cho ngăn xếp mạng để tiếp cận localhost. Hãy thận trọng với phương pháp này vì có một vài yếu tố sẽ xuất hiện trên hệ điều hành máy chủ. Chẳng hạn như số lượng tệp đang mở, v.v.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.