Tại sao nginx phản hồi với bất kỳ tên miền nào?


139

Tôi có nginx và chạy với ứng dụng Ruby / Sinatra và tất cả đều ổn. Tuy nhiên, bây giờ tôi đang cố gắng để có một ứng dụng thứ hai chạy từ cùng một máy chủ và tôi nhận thấy một điều kỳ lạ. Đầu tiên, đây là nginx.conf của tôi:

pid /tmp/nginx.pid;
error_log /tmp/nginx.error.log;

events {
  worker_connections 1024;
  accept_mutex off;
}

http {
  default_type application/octet-stream;
  access_log /tmp/nginx.access.log combined;

  sendfile on;
  tcp_nopush on;
  tcp_nodelay off;

  gzip on;
  gzip_http_version 1.0;
  gzip_proxied any;
  gzip_min_length 500;
  gzip_disable "MSIE [1-6]\.";
  gzip_types text/plain text/xml text/css
             text/comma-separated-values
             text/javascript application/x-javascript
             application/atom+xml;

  upstream app {
    server unix:/var/www/app/tmp/sockets/unicorn.sock fail_timeout=0;
  }

  server {
    listen 80;
    client_max_body_size 4G;
    server_name FAKE.COM;

    keepalive_timeout 5;

    root /var/www/app/public;

    location / {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;

      if (!-f $request_filename) {
        proxy_pass http://app;
        break;
      }
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/app/public;
    }
  }
}
                                                          68,0-1        B

Lưu ý cách server_namecài đặt thành FAKE.COMmáy chủ đang phản hồi với tất cả các máy chủ truy cập máy chủ đó thông qua các tên miền khác. Làm cách nào tôi có thể khiến máy chủ cụ thể đó chỉ phản hồi các yêu cầu FAKE.COM?


các listen fake.com | something.com:80 bộ lọc lệnh, không server_name.
Alexei Martigan

Câu trả lời:


202

Khối máy chủ đầu tiên trong cấu hình nginx là mặc định cho tất cả các yêu cầu tấn công máy chủ không có khối máy chủ cụ thể.

Vì vậy, trong cấu hình của bạn, giả sử tên miền thực của bạn là REAL.COM, khi người dùng nhập vào, nó sẽ phân giải đến máy chủ của bạn và vì không có khối máy chủ nào cho thiết lập này, nên khối máy chủ cho FAKE.COM, là khối đầu tiên khối máy chủ (chỉ khối máy chủ trong trường hợp của bạn), sẽ xử lý yêu cầu đó.

Đây là lý do tại sao các cấu hình Nginx thích hợp có một khối máy chủ cụ thể để mặc định trước khi theo dõi với các tên miền cụ thể khác.

# Default server
server {
    return 404;
}

server {
    server_name domain_1;
    [...]
}

server {
    server_name domain_2;
    [...]
}

Vân vân

** BIÊN TẬP **

Có vẻ như một số người dùng hơi bối rối với ví dụ này và nghĩ rằng nó bị giới hạn trong một tệp conf, v.v.

Xin lưu ý rằng ở trên là một ví dụ đơn giản để OP phát triển theo yêu cầu.

Cá nhân tôi sử dụng các tệp conf vhost riêng biệt với điều này (CentOS / RHEL):

http {
    [...]
    # Default server
    server {
        return 404;
    }
    # Other servers
    include /etc/nginx/conf.d/*.conf;
}

/etc/nginx/conf.d/ sẽ chứa domain_1.conf, domain_2.conf ... domain_n.conf sẽ được bao gồm sau khối máy chủ trong tệp nginx.conf chính sẽ luôn là đầu tiên và sẽ luôn là mặc định trừ khi được ghi đè bằng default_server chỉ thị ở nơi khác

Thứ tự chữ cái của tên tệp của các tệp conf cho các máy chủ khác trở nên không liên quan trong trường hợp này.

Ngoài ra, sự sắp xếp này mang lại rất nhiều tính linh hoạt ở chỗ có thể xác định nhiều mặc định.

Trong trường hợp cụ thể của tôi, tôi chỉ nghe Apache trên Cổng 8080 trên giao diện nội bộ và tôi ủy quyền các tập lệnh PHP và Perl cho Apache.

Tuy nhiên, tôi chạy hai ứng dụng riêng biệt có cả liên kết trả về với ": 8080" trong html đầu ra được đính kèm khi chúng phát hiện ra rằng Apache không chạy trên Cổng 80 tiêu chuẩn và cố gắng "giúp đỡ" tôi.

Điều này gây ra một vấn đề ở chỗ các liên kết trở nên không hợp lệ vì không thể truy cập Apache từ giao diện bên ngoài và các liên kết sẽ trỏ đến Cổng 80.

Tôi giải quyết điều này bằng cách tạo một máy chủ mặc định cho Cổng 8080 để chuyển hướng các yêu cầu đó.

http {
    [...]
    # Default server block for undefined domains
    server {
        listen 80;
        return 404;
    }
    # Default server block to redirect Port 8080 for all domains
    server {
        listen my.external.ip.addr:8080;
        return 301 http://$host$request_uri;
    }
    # Other servers
    include /etc/nginx/conf.d/*.conf;
}

Vì không có gì trong các khối máy chủ thông thường lắng nghe trên Cổng 8080, khối máy chủ mặc định chuyển hướng xử lý một cách minh bạch các yêu cầu như vậy nhờ vào vị trí của nó trong nginx.conf.

Tôi thực sự có bốn khối máy chủ như vậy và đây là trường hợp sử dụng đơn giản hóa.


1
Nginx yêu cầu phân biệt chữ hoa chữ thường - "Máy chủ" phải là máy chủ và "Trả về" sẽ được trả về. Hy vọng điều này sẽ tiết kiệm một vài rắc rối khi sao chép mã này.
Capaj

2
tĩnh, xem câu trả lời của Oleg Neumyvkin - nếu bạn có nhiều tệp cấu hình trong các trang có sẵn, thì máy chủ đầu tiên trong tệp đầu tiên theo thứ tự bảng chữ cái là mặc định của bạn. Tôi nghi ngờ đây có thể là một vấn đề. Ngoài ra, nhiều bản phân phối chạy 'nginx -t' để kiểm tra cấu hình trước khi khởi động lại - bạn có thể gặp lỗi khi khởi động lại.
jwhitlock

2
Điều này là không đầy đủ và không nên là câu trả lời được chấp nhận. Để làm việc này, bạn cũng sẽ phải xóa default_server khỏi mọi chỉ thị lắng nghe.
Ben

@ben Trước tiên, OP không có "default_server" trong ví dụ vấn đề của anh ấy và câu trả lời được điều chỉnh theo các chi tiết cụ thể của câu hỏi đó. Thứ hai, tại sao mọi người sẽ xác định default_server trên một vị trí máy chủ riêng biệt khi làm theo các hướng dẫn để làm cho máy chủ được xác định đầu tiên, mặc định nằm ngoài tôi. Trong mọi trường hợp, nếu một default_server đã được xác định cụ thể, thì bộ Q / A này không phải là thứ cần xem xét để giải quyết bất kỳ vấn đề nào họ có thể gặp phải.
Dayo

1
@Dayo Bạn đúng là bạn đã giải quyết cấu hình cụ thể được đăng bởi OP. Nhưng để có câu trả lời đầy đủ cho câu hỏi, tôi nghĩ cần phải đề cập đến default_server. Rất có thể đọc câu trả lời của bạn và không nhận ra default_server sẽ can thiệp vào nó như thế nào. Nó thậm chí còn có khả năng hơn vì một số bản phân phối vận chuyển với default_server được xác định trong một tệp có thể không rõ ràng đối với người dùng.
Ben

61

Bạn nên có một máy chủ mặc định để bắt tất cả , bạn có thể trả lại 404hoặc tốt hơn là không phản hồi gì cả (sẽ tiết kiệm một số băng thông) bằng cách trả lại 444phản hồi HTTP cụ thể nginx chỉ đơn giản là đóng kết nối và không trả về

server {
    listen       80  default_server;
    server_name  _; # some invalid name that won't match anything
    return       444;
}

Làm việc cho tôi cho nginx 1.8.0. Các server_name _;tôi không có trong các phiên bản trước đó cho nginx, nhưng nó làm việc. Bây giờ đối với các phiên bản nginx mới hơn, có vẻ như bạn cần server_name _;. Cảm ơn
daniel

Giải quyết. Tôi quên một dấu chấm phẩy; _;
dùng1201917

2
@iTech: Vì một số lý do, nó sẽ trả lại 444 cho tất cả các yêu cầu. Bất kì manh mối nào?
Divick

Mẹo tuyệt vời về 444, và imho một giải pháp sạch hơn nhiều so với trả lại mã lỗi.
qqilihq

1
Điều quan trọng là chỉ định chứng chỉ / khóa, nếu không, tất cả các kết nối SSL sẽ khớp và không thành công, như được chỉ ra bởi @AndreyT trong câu trả lời của anh ấy bên dưới.
Đánh dấu Fletcher

35

Tôi không thể giải quyết vấn đề của mình với bất kỳ câu trả lời nào khác. Tôi đã giải quyết vấn đề bằng cách kiểm tra xem máy chủ có khớp hay không và trả lại 403 nếu không. (Tôi có một số trang web ngẫu nhiên trỏ đến nội dung máy chủ web của mình. Tôi đoán là chiếm quyền điều khiển tìm kiếm)

server {
    listen 443;
    server_name example.com;

    if ($host != "example.com") {
        return 403;
    }

    ...
}

1
Nếu là một thực tiễn xấu: nginx.com/resource/wiki/start/topics/depth/ifisevil
Esolitos

1
Có những trường hợp đơn giản là bạn không thể tránh sử dụng if, ví dụ, nếu bạn cần kiểm tra một biến không có chỉ thị tương đương.
Edward

4
@Esolitos Nghĩa đen là dòng thứ ba của bài viết đó nói rằng trường hợp sử dụng này là ổn. Tôi hiểu sự cần thiết phải thận trọng, nhưng chúng ta đừng vẫy tay trong các trường hợp sử dụng hợp lý.
bắt đầu

Theo tôi, giải pháp đơn giản và ngắn gọn nhất, vì nó chỉ yêu cầu 3 dòng mã bạn có thể vui lòng dán vào bất kỳ tệp vhost nào, chỉ thay đổi máy chủ $ được so sánh sau đó.
Akito

28

Để trả lời câu hỏi của bạn - nginx chọn máy chủ đầu tiên nếu không có kết quả khớp. Xem tài liệu :

Nếu giá trị của nó không khớp với bất kỳ tên máy chủ nào hoặc yêu cầu hoàn toàn không chứa trường tiêu đề này, thì nginx sẽ định tuyến yêu cầu đến máy chủ mặc định cho cổng này. Trong cấu hình trên, máy chủ mặc định là máy chủ đầu tiên ...

Bây giờ, nếu bạn muốn có một máy chủ bắt tất cả mặc định, giả sử, đáp ứng với 404 cho tất cả các yêu cầu, thì đây là cách thực hiện:

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_certificate <path to cert>
    ssl_certificate_key <path to key>
    return 404;
}

Lưu ý rằng bạn cần chỉ định chứng chỉ / khóa (có thể tự ký), nếu không tất cả các kết nối SSL sẽ không thành công vì nginx sẽ cố gắng chấp nhận kết nối bằng default_server này và sẽ không tìm thấy cert / key.


3
Tôi không biết tại sao câu trả lời này là quá xa trong danh sách. Đây là câu trả lời cho câu hỏi mà không bị phân tâm bởi những thứ sáng bóng trên đường đi.
mmc

Điều này giúp tôi giải quyết vấn đề khi tôi đang thử chuyển hướng từ không phải www sang www mà tôi phải đưa chứng chỉ ssl của mình vào tuyến chuyển hướng này nếu không thì đang cố lấy chứng chỉ ssl mặc định của tôi cho một tên miền khác.
thúc

1
Đây có vẻ như là câu trả lời tốt nhất cho hầu hết các cấu hình ... không chắc ai đang sử dụng nginx mà không có SSL trong những ngày này, nhưng thực tế đây là cách duy nhất bao gồm SSL là cực kỳ đáng nói.
bắt đầu

Dường như điều đó server_name _;thậm chí không cần thiết.
Julien Salinas

26

Có một số cách để chỉ định máy chủ mặc định.

Cách thứ nhất - Chỉ định máy chủ mặc định đầu tiên trong danh sách, nếu bạn giữ cấu hình máy chủ của mình trong một tệp cấu hình, như Dayo hiển thị ở trên.

Cách thứ hai (tốt hơn) Linh hoạt hơn - cung cấp default_servertham số cho listenhướng dẫn, ví dụ:

server {
    listen  *:80 default_server;
    root /www/project/public/;
}

Thêm thông tin tại đây: Nginx doc / Nghe

Cách này hữu ích hơn khi bạn giữ cấu hình máy chủ trong các tệp riêng biệt và không muốn đặt tên cho các tệp đó theo thứ tự bảng chữ cái.


3
Đây phải là câu trả lời chính xác. Câu trả lời được chấp nhận là sai lệch. Chỉ cần thêm một máy chủ khác vào cấu hình sẽ không giải quyết được vấn đề nếu một máy chủ khác được cấu hình là máy chủ mặc định.
Ben

1
@Pavel không có lý do tại sao câu trả lời được cung cấp không thể hoạt động với nhiều tệp vhost riêng biệt. Ngoài ra, với điều này, tôi biết rằng máy chủ mặc định của tôi luôn nằm trong tệp nginx.conf chính và không phải nhớ một trong nhiều tệp vhost riêng biệt của tôi có chứa tệp này.
Dayo

Đừng quên lắng nghe 443 cũng như ssl (xem phản hồi của @ AndreyT bên dưới).
Constantinos

8

Ít bình luận để trả lời:

nếu bạn có một số máy chủ ảo trên một số IP trong một số tệp cấu hình trong các trang có sẵn /, thì miền "mặc định" cho IP sẽ được lấy từ tệp đầu tiên theo thứ tự chữ cái.

Và như Pavel đã nói, có đối số "default_server" cho chỉ thị "lắng nghe" http://nginx.org/en/docs/http/ngx_http_core_module.html#listen

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.