Tạo nginx để vượt qua tên máy chủ của dòng ngược khi đảo ngược


89

Tôi chạy một số container docker với tên máy chủ:

web1.local web2.local web3.local

Định tuyến đến những cái này được thực hiện dựa trên tên máy chủ của nginx. Tôi có một proxy trước thiết lập này (trên máy khác được kết nối với internet) nơi tôi xác định ngược dòng là:

    upstream main {
      server web1.local:80;
      server web2.local:80;
      server web3.local:80;
    }

Và mô tả máy chủ ảo thực tế:

    server {
      listen 80;
      server_name example.com;
      location / {
        proxy_pass http://main;
      }
    }

Bây giờ, vì các container nhận tên máy chủ "chính" thay vì "web1.local", chúng không đáp ứng đúng với yêu cầu.

Câu hỏi: làm thế nào tôi có thể yêu cầu nginx chuyển tên của máy chủ ngược dòng thay vì tên của nhóm máy chủ ngược dòng trong Máy chủ: tiêu đề khi yêu cầu ủy quyền?


3
Tôi không nghĩ bạn có thể. Tại sao bạn không đặt máy chủ phụ trợ của mình để phản hồi với main hoặc example.com? Không phải là nếu phụ trợ không biết đó là ai. Điều ngược lại là có thể: proxy_set_header Host $ host; sẽ thay thế bất kỳ biến chủ nào quay trở lại từ thượng nguồn bằng tên máy chủ từ yêu cầu ban đầu.
Andrew Domaszek

Điều thích hợp để làm là sửa ứng dụng.
Michael Hampton

Câu trả lời:


109

Thực tế bạn có thể làm điều đó thông qua proxy_set_header.

Để biết thêm chi tiết, hãy xem tại đây: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header hoặc xem trường hợp sử dụng ví dụ tại đây: https://stackoverflow.com/questions/12847771/configure-nginx- với proxy-pass

Tôi đã bao gồm cách tiếp cận năng động vào cấu hình được đăng ở trên của bạn:

server {
  listen 80;
  server_name example.com;
  location / {
    proxy_pass       http://main;
    proxy_set_header Host            $host;
    proxy_set_header X-Forwarded-For $remote_addr;
  }
}

Dưới đây là một ví dụ với tên máy chủ tĩnh:

server {
  listen 80;
  server_name example.com;
  location / {
    proxy_pass       http://main;
    proxy_set_header Host            www.example.com;
    proxy_set_header X-Forwarded-For $remote_addr;
  }
}

7
proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for; có vẻ tốt hơn
sivann

1
@pavel: hiểu rồi Thật ra tôi cũng đã làm một số nghiên cứu và một số bài kiểm tra. Dường như không có cách tiếp cận thẳng để thực hiện yêu cầu của bạn. Vì vậy, ngay cả một giải pháp "bastardized" là một giải pháp. Tôi không muốn hỏi tại sao bạn muốn làm điều này. Tôi khá chắc chắn rằng bạn có lý do của bạn. :-)
Jens Bradler

@JensBradler Bạn có vẻ chuyên gia hơn tôi rất nhiều, bạn có thể cho tôi biết bạn nghĩ gì về giải pháp của tôi không? Tôi muốn làm như vậy bởi vì tôi chạy hai bản sao của trang web của tôi từ hai tài khoản trên ISP của tôi: site1.myisp.comsite2.myisp.comvà họ chỉ phản ứng với tên tương ứng của họ. Bây giờ, tôi sở hữu tên miền của mình và tôi muốn sử dụng trang web ISP của mình để tải cân bằng các máy chủ của mình. Đó không phải là một lý do tốt? Cảm ơn bạn rất nhiều;)
ncenerar

1
@ncenerar Bạn có thể làm điều đó nhưng điều này sẽ đưa bạn đến một điểm thất bại duy nhất: bộ cân bằng tải. Nếu điều này là để cân bằng tải (không phải dự phòng), bạn cũng có thể sử dụng cân bằng tải dựa trên DNS kết hợp với chuyển đổi dự phòng DNS.
Jens Bradler

2
Câu trả lời này phản ánh lời khuyên của blog chính thức .
Bernard Rosset

28

Tôi đã có cùng một vấn đề và cuối cùng tôi đã giải quyết nó bằng cách sử dụng hai cấp độ proxy. Đây là cách bạn có thể làm cho tình huống của mình (tôi nghĩ):

server {
  listen      8001 default_server;
  server_name web1.example.com;
  location / {
    proxy_pass       http://web1.local:80;
    proxy_set_header Host web1.local:80;
  }
}

server {
  listen      8002 default_server;
  server_name web2.example.com;
  location / {
    proxy_pass       http://web2.local:80;
    proxy_set_header Host web2.local:80;
  }
}

server {
  listen      8003 default_server;
  server_name web3.example.com;
  location / {
    proxy_pass       http://web3.local:80;
    proxy_set_header Host web3.local:80;
  }
}

upstream main {
  server 127.0.0.1:8001;
  server 127.0.0.1:8002;
  server 127.0.0.1:8003;
}

server {
  listen      80;
  server_name example.com;
  location / {
    proxy_pass http://main;
  }
}

Như bạn có thể thấy, mẹo là tạo một máy chủ cục bộ đáp ứng với một cổng cụ thể sẽ ủy quyền cho máy chủ bằng cách viết lại Máy chủ phù hợp cho mỗi máy chủ. Sau đó, bạn có thể sử dụng máy chủ cục bộ này trong thượng nguồn của mình và cuối cùng sử dụng ngược dòng đó trong proxy thực.


Ban đầu tôi đã sử dụng phương pháp Lua, nhưng bây giờ đã chuyển hoàn toàn sang HAProxy, cho phép thực hiện đúng những gì tôi muốn với cấu hình tiêu chuẩn.
pavel_karoukin

3

Vì vậy, từ việc đọc tất cả tài liệu cho nginx (tôi thực sự không thể phân tích mã cho mô-đun ngược dòng = () Tôi đã đưa ra giải pháp bastardized này. Vì vậy, tôi phải thiết lập một số loại giám sát để đảm bảo tất cả các phụ trợ đang chạy.

server {
        listen 80;
        server_name example.com;
        resolver 127.0.0.1;

        location / {
                set $upstream "";
                rewrite_by_lua '
                        local upstreams = {
                                "http://web1.dokku.localdomain",
                                "http://web2.dokku.localdomain",
                                "http://web3.dokku.localdomain",
                                "http://web4.dokku.localdomain"
                        }
                        ngx.var.upstream = upstreams[ math.random( #upstreams ) ] 
                ';
                proxy_pass $upstream;
        }
}

2

Chúng tôi chuyển vào phần bổ sung ngược dòng dưới dạng một tiêu đề riêng như thế này

server {
  listen 80;
  server_name example.com;
  location / {
    proxy_pass       http://main;
    proxy_set_header Host            $host;
    proxy_set_header X-Forwarded-For $remote_addr;
    add_header       X-Upstream      $upstream_addr;
  }
}

Nếu bạn đã thử thì sao?

server {
  listen 80;
  server_name example.com;
  location / {
    proxy_pass       http://main;
    proxy_set_header Host            $upstream_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    add_header       X-Host          $host;
  }
}

2

Mặc dù mục tiêu có vẻ hợp lý, nginx sẽ không thay đổi tiêu đề Host: để phù hợp với ngược dòng . Thay vào đó, nó xử lý các upstreamtên miền như CNAMEtrong DNS - như một cách để đến địa chỉ IP.

Các tiêu đề yêu cầu (và cơ thể) được cố định trước khi ngược dòng được chọn. Thượng nguồn có thể thay đổi yêu cầu giữa nếu yêu cầu ngược dòng cụ thể là không đáp ứng, nhưng yêu cầu không thay đổi.


0

Hừm. Tôi có một thiết lập tương tự, trong đó tôi chỉ đơn giản là thực hiện

location / {
    ... 
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_pass ...;
}

Việc sử dụng $http_host(tiêu đề Máy chủ HTTP từ yêu cầu đến) ở đây chứ không phải $host(cấu hình tên máy chủ của máy chủ) khiến cho tiêu đề Máy chủ tương tự được khách hàng chuyển đến ngược dòng, trong thử nghiệm của tôi.

Xem thêm https://stackoverflow.com/questions/14352690/change-host-header-in-nginx-reverse-proxy .


0

Vì những người khác đã đăng bài bằng cách sử dụng biến tập lệnh (như $ ngược dòng), bạn có thể đặt nó theo cách bạn muốn và điều đó sẽ khắc phục vấn đề, mà không cần hack thêm tiêu đề.

Proxy Pass xử lý các biến kịch bản đe dọa theo một cách khác, nếu một giá trị không có điều kiện (không có $ trong tên) được sao lưu ngược dòng trong giai đoạn cấu hình và sử dụng sau.

Một cách đơn giản để bỏ qua vấn đề này và có những ưu điểm nhất của (phiên bản miễn phí) ngược dòng sẽ là sử dụng một cái gì đó như Split_Clients:

split_clients $request_uri $my_upstream {
              33%          server1.domainX.com;
              33%          server2.domainX.com;
# Always use DOT at end entry if you wonder why, read the SC code.
              *            server3.domainX.com;  
}
location / {
    ... 
    proxy_pass http://$my_upstream;
}

Ví dụ trên trông gần giống như ngược dòng. Có tồn tại các mô-đun khác thực hiện ánh xạ, tức là chash_map_module , nhưng vì chúng nằm ngoài cây nên bạn sẽ cần tự xây dựng chúng, điều này không thể thực hiện được đối với một số trường hợp sử dụng /

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.