Làm cách nào để viết lại URL trong phản hồi proxy trong NGINX


86

Tôi đã quen sử dụng Apache với mod_proxy_html và đang cố gắng đạt được điều gì đó tương tự với NGINX. Trường hợp sử dụng cụ thể là tôi có giao diện người dùng quản trị chạy trong Tomcat trên cổng 8080 trên máy chủ ở ngữ cảnh gốc:

http://localhost:8080/

Tôi cần hiển thị điều này trên cổng 80, nhưng tôi có các ngữ cảnh khác trên máy chủ NGINX đang chạy trên máy chủ này, vì vậy tôi muốn thử và truy cập vào tại:

http://localhost:80/admin/

Tôi đã hy vọng rằng khối máy chủ siêu đơn giản sau sẽ làm được điều đó, nhưng nó không hoàn toàn:

server {
    listen  80;
    server_name screenly.local.akana.com;

    location /admin/ {
        proxy_pass http://localhost:8080/;
    }
}

Vấn đề là nội dung trả về (html) chứa URL đến tập lệnh và thông tin kiểu đều được truy cập ở ngữ cảnh gốc, vì vậy tôi cần viết lại các URL này để bắt đầu bằng / admin / thay vì /.

Làm cách nào để thực hiện việc này trong NGINX?

Câu trả lời:


121

Trước tiên, chúng ta nên đọc kỹ và đầy đủ tài liệu về proxy_pass .

URI được chuyển đến máy chủ ngược dòng được xác định dựa trên việc chỉ thị "proxy_pass" có được sử dụng với URI hay không. Dấu gạch chéo trong chỉ thị proxy_pass có nghĩa là URI hiện diện và bằng /. Sự xuất hiện của dấu gạch chéo có nghĩa là URI mũ không có.

Proxy_pass với URI :

location /some_dir/ {
    proxy_pass http://some_server/;
}

Với phần trên, có proxy sau:

http:// your_server/some_dir/ some_subdir/some_file ->
http:// some_server/          some_subdir/some_file

Về cơ bản, /some_dir/được thay thế bằng /để thay đổi đường dẫn yêu cầu từ /some_dir/some_subdir/some_filethành /some_subdir/some_file.

Proxy_pass không có URI :

location /some_dir/ {
    proxy_pass http://some_server;
}

Với dấu thứ hai (không có dấu gạch chéo): proxy sẽ như thế này:

http:// your_server /some_dir/some_subdir/some_file ->
http:// some_server /some_dir/some_subdir/some_file

Về cơ bản, đường dẫn yêu cầu ban đầu đầy đủ được truyền mà không có thay đổi.


Vì vậy, trong trường hợp của bạn, có vẻ như bạn chỉ nên bỏ dấu gạch chéo để đạt được những gì bạn muốn.


Cảnh báo trước

Lưu ý rằng tự động ghi lại chỉ hoạt động nếu bạn không sử dụng các biến trong proxy_pass. Nếu bạn sử dụng các biến, bạn nên tự viết lại:

location /some_dir/ {
  rewrite    /some_dir/(.*) /$1 break;
  proxy_pass $upstream_server;
}

Có những trường hợp khác mà việc viết lại sẽ không hoạt động, đó là lý do tại sao việc đọc tài liệu là điều bắt buộc.


Biên tập

Đọc lại câu hỏi của bạn, có vẻ như tôi có thể đã bỏ lỡ rằng bạn chỉ muốn chỉnh sửa đầu ra html.

Đối với điều đó, bạn có thể sử dụng chỉ thị sub_filter . Cái gì đó như ...

location /admin/ {
    proxy_pass http://localhost:8080/;
    sub_filter "http://your_server/" "http://your_server/admin/";
    sub_filter_once off;
}

Về cơ bản, chuỗi bạn muốn thay thế và chuỗi thay thế


2
Cảm ơn, điều đó sẽ giúp rất nhiều. Tôi nghĩ sub_filter sẽ làm được.
IanG

2
Tôi rất tò mò đến mức độ nào mà nginx đã viết lại đầu ra, woudl không phải tối thiểu phải viết lại tên máy chủ / tên máy chủ trong các liên kết? Vì vậy, ví dụ, bạn sẽ khôngsub_filter "http://localhost/" "http://localhost/admin/"
ThorSummoner

1
Để cho phép viết lại ngoài text/htmlmimetype, tôi cũng phải thêm vào sub_filter_types *;.
anttikoo

Có điều gì đó kỳ lạ đang xảy ra với tôi với giải pháp này. Tài nguyên (* .js, * .css, v.v. đang được tìm nạp), nhưng trang không tải được. tôi mong đợi http://your_server/admin/sẽ được giải quyết http://your_servertrong quá trình proxy_pass nhưng nó không được và tôi gặp lỗi react-router /admin/ location did not match any routestrong ứng dụng của mình vì ứng dụng của tôi không biết gì về '/ admin'.
Prachi

Bạn cũng có thể cần thêm proxy_redirectchỉ thị để Locationtiêu đề được gửi bởi phản hồi cũng được sửa đổi phù hợp với url. Xem hướng dẫn này: cyberciti.biz/faq/…
vivanov

21

Bạn cũng có thể cần đặt lệnh sau trước "sub_filter" đầu tiên cho máy chủ phụ trợ có nén dữ liệu:

proxy_set_header Accept-Encoding "";

Nếu không, nó có thể không hoạt động. Đối với ví dụ của bạn, nó sẽ giống như sau:

location /admin/ {
    proxy_pass http://localhost:8080/;
    proxy_set_header Accept-Encoding "";
    sub_filter "http://your_server/" "http://your_server/admin/";
    sub_filter_once off;
}

-2

Bạn có thể sử dụng ví dụ cấu hình nginx sau:

upstream adminhost {
  server adminhostname:8080;
}

server {
  listen 80;

  location ~ ^/admin/(.*)$ {
    proxy_pass http://adminhost/$1$is_args$args;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $server_name;
  }
}

1
Tại sao điều này bị phản đối? Bất kỳ vấn đề với mã? Có vẻ như đây là một giải pháp tốt và phức tạp đối với tôi, giải quyết một số cảnh báo về việc ủy ​​quyền một ứng dụng bật lên sau này. Tuy nhiên, không chắc tại sao proxy_redirect off;. Ngoài ra, tôi muốn thêm proxy_set_header X-Forwarded-Proto $scheme;.
LuH
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.