Câu hỏi Trong Nginx, làm thế nào tôi có thể viết lại tất cả các yêu cầu http để https trong khi duy trì tên miền phụ?


Tôi muốn viết lại tất cả các yêu cầu http trên máy chủ web của mình là các yêu cầu https, tôi bắt đầu với những điều sau:

máy chủ {
    nghe 80;

    vị trí / {
      viết lại ^ (. *) https: //mysite.com$1 vĩnh viễn;
    }
...


Một vấn đề là việc này loại bỏ mọi thông tin tên miền phụ (ví dụ: node1.mysite.com/folder), làm thế nào tôi có thể viết lại ở trên để định tuyến lại mọi thứ tới https và duy trì tên miền phụ?


495
2017-09-21 14:04


gốc


Vui lòng xem xét chuyển 'câu trả lời được chấp nhận' thành serverfault.com/a/171238/90758. Đó là một trong những chính xác. - olafure
Chỉ cần sử dụng $ server_name thay vì hardsite được mã hóa mysite.com - Fedir RYKHTIK


Các câu trả lời:


Cách chính xác trong các phiên bản mới của nginx

Hóa ra câu trả lời đầu tiên của tôi cho câu hỏi này là chính xác vào thời điểm nào đó, nhưng nó trở thành một cạm bẫy khác - để luôn cập nhật, hãy kiểm tra Thuế viết lại cạm bẫy

Tôi đã được sửa chữa bởi nhiều người dùng SE, vì vậy tín dụng sẽ đến với họ, nhưng quan trọng hơn, đây là mã chính xác:

server {
       listen         80;
       server_name    my.domain.com;
       return         301 https://$server_name$request_uri;
}

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000" always; 

       [....]
}

737
2017-12-05 20:43



Bạn sẽ phải làm điều này trên một tên miền theo cơ sở miền tuy nhiên - không? Điều gì sẽ xảy ra nếu bạn muốn áp dụng nó cho mọi miền trên máy chủ của mình? - JM4
@ JM4: nếu bạn sử dụng $ host $ trong ghi đè thay vì server_name và thêm default_server vào chỉ thị nghe, nó sẽ hoạt động cho mọi miền trên máy chủ của bạn. - Klaas van Schelven
Điều quan trọng cần lưu ý là 301 được lưu trữ trong bộ nhớ cache cục bộ của bạn mà không có ngày hết hạn. Không hữu ích khi định cấu hình thay đổi - Trefex
@everyone Sử dụng chuyển hướng 307 để duy trì nội dung POST. - Mahmoud Al-Qudsi
Lưu ý rằng bạn phải sử dụng $host thay vì $server_name nếu bạn đang sử dụng tên miền phụ. - Catfish


LƯU Ý: Cách tốt nhất để làm điều này được cung cấp bởi https://serverfault.com/a/401632/3641 - nhưng được lặp lại ở đây:

server {
    listen         80;
    return 301 https://$host$request_uri;
}

Trong trường hợp đơn giản nhất, máy chủ của bạn sẽ được sửa là dịch vụ bạn muốn gửi cho họ - điều này sẽ chuyển hướng 301 tới trình duyệt và URL trình duyệt sẽ cập nhật tương ứng.

Dưới đây là câu trả lời trước, đó là không hiệu quả do regex, một 301 đơn giản là tuyệt vời như được hiển thị bởi @kmindi

Tôi đã sử dụng nginx 0.8.39 trở lên và được sử dụng như sau:

 server {
       listen 80;
       rewrite ^(.*) https://$host$1 permanent;
 }

Gửi một chuyển hướng vĩnh viễn cho khách hàng.


269
2017-08-17 03:07



Tôi nghĩ rằng nó phải là 80 - vì đây là lắng nghe cho http và sau đó nói với khách hàng để trở lại như https (443). - Michael Neale
Đây sẽ là câu trả lời hàng đầu! - Nathan
Đây là câu trả lời nhất về thuế. - Case
đây là cách dễ nhất, nhưng ít an toàn nhất - theo cách này bạn cho phép máy chủ chuyển hướng người dùng đến bất kỳ trang nào mà không kiểm tra xem nó có được phép sử dụng trên máy chủ của bạn hay không. Nếu máy chủ của bạn phục vụ mydomain.co, người dùng độc hại vẫn có thể sử dụng máy chủ của bạn để chuyển hướng người dùng đến các miền khác như mydomain.co, chẳng hạn như google.com. - friedkiwi
@ cab0lt không có vấn đề bảo mật ở đây. Cung cấp chuyển hướng không thể hiện nguy cơ bảo mật. Nếu có các yêu cầu kiểm soát truy cập, các yêu cầu này sẽ được kiểm tra tại thời điểm trình duyệt yêu cầu URL mới. Trình duyệt sẽ không được truy cập đơn giản trên cơ sở chuyển hướng, cũng không cần chuyển hướng để yêu cầu URL mới. - mc0e


Tôi nghĩ cách tốt nhất và duy nhất nên sử dụng HTTP 301 đã chuyển vĩnh viễn chuyển hướng như thế này:

server {
    listen         [::]:80;
    return 301 https://$host$request_uri;
}

Các HTTP 301 đã chuyển vĩnh viễn chuyển hướng cũng là hiệu quả nhất vì không có regex để được đánh giá, theo đã đề cập pitfails.


Cái mới HTTP 308 đã chuyển vĩnh viễn giữ nguyên phương thức Request và là được hỗ trợ bởi các trình duyệt chính. Ví dụ: sử dụng 308 ngăn các trình duyệt thay đổi phương thức yêu cầu từ POST đến GET cho yêu cầu chuyển hướng.


Nếu bạn muốn giữ tên máy chủ và tên miền phụ đây là cách.

Điều này vẫn hoạt động nếu bạn không có DNS, vì tôi cũng sử dụng nó cục bộ. Tôi đang yêu cầu ví dụ với http://192.168.0.100/index.php và sẽ được chuyển hướng đến chính xác https://192.168.0.100/index.php.

tôi sử dụng listen [::]:80 trên máy chủ của tôi vì tôi có bindv6only đặt thành false, vì vậy nó cũng liên kết với ổ cắm ipv4. thay đổi nó thành listen 80 nếu bạn không muốn IPv6 hoặc muốn liên kết ở nơi khác.

Các giải pháp từ Saif Bechan sử dụng server_name trong trường hợp của tôi là localhost nhưng không thể truy cập qua mạng.

Các giải pháp từ Michael Neale là tốt, nhưng theo pitfails, có một giải pháp tốt hơn với chuyển hướng 301;)


121
2018-06-23 17:19



Tốt đẹp bạn cố gắng trích dẫn nó, nhưng 301 không hoạt động trên HTTPS. - Case
những gì không hoạt động? phần máy chủ đã nêu là dành cho lưu lượng truy cập không được mã hóa http (không có s) để được chuyển hướng vĩnh viễn đến máy chủ được mã hóa (phần mà nghe trên 443 (https) không được liệt kê) - kmindi
Tôi đã kiểm tra này hoạt động tuyệt vời với https và tất cả mọi thứ - @kmindi Tôi cập nhật câu trả lời của tôi với tham chiếu đến của bạn - như tôi nghĩ rằng đó là đúng cách và điều này giữ popping lên! Công việc tốt đẹp. - Michael Neale
Khi sử dụng yêu cầu miền (không phải ip), không hoạt động trừ khi tôi thay đổi '[::]: 80' thành '80'. - Joseph Lust
đó có thể là hành vi mong đợi: trac.nginx.org/nginx/ticket/345. Tôi đã cập nhật câu trả lời để mô tả tùy chọn nghe. - kmindi


Ở trên không làm việc cho với với các tên miền phụ mới được tạo ra tất cả các thời gian. ví dụ. AAA.example.com BBB.example.com cho khoảng 30 tên miền phụ.

Cuối cùng có một cấu hình làm việc với những điều sau đây:

server {
  listen 80;
  server_name _;
  rewrite ^ https://$host$request_uri? permanent;
}
server {
  listen  443;
  server_name example.com;
  ssl on;
  ssl_certificate /etc/ssl/certs/myssl.crt;
  ssl_certificate_key /etc/ssl/private/myssl.key;
  ssl_prefer_server_ciphers       on;
# ...
# rest of config here
# ...
}

17
2018-06-25 04:29



cảm ơn bạn! nginx sẽ trở lại 301 https://*/ hoặc hủy yêu cầu sớm trong các câu trả lời khác tại đây. server_name _; với $host là câu trả lời đã làm các trick. +1 - zamnuts
Cái này là tối ưu! Tuy nhiên, tôi khuyên bạn nên thay thế _ với tên miền thực tế, ví dụ: .domain.com Tôi đã có hai máy chủ, và nginx đã vô tình chỉ đạo một trong các máy chủ của tôi đến máy chủ mặc định. - zzz
Đây là câu trả lời duy nhất làm việc cho tôi, cảm ơn! - Snowman
Cảm ơn bạn rất nhiều .. Tôi đã thử nhiều giải pháp nhưng không làm việc. Giải pháp này là tuyệt vời và nó đã làm việc cho tôi. tên máy chủ _; điều này có nghĩa là gì .. Tôi không hiểu. Xin hãy giải thích cho tôi điều này. - Pavan Kumar


Trong khối máy chủ, bạn cũng có thể thực hiện các thao tác sau:

# Force HTTPS connection. This rules is domain agnostic
if ($scheme != "https") {
    rewrite ^ https://$host$uri permanent;
}

16
2017-07-31 19:50



Cấu hình này khiến máy chủ của tôi tạo ra vòng lặp chuyển hướng - Corkscreewe
Có thể gây ra một chuyển hướng khác hoặc https không được bật trong trang web / ứng dụng của bạn - Oriol
Không ai trong số những người khác dường như làm việc ngoại trừ cái này. Sử dụng phiên bản nginx: nginx / 1.10.0 (Ubuntu) - ThatGuy343
upvoted cho https: // $ host $ uri - AMB
Đây là con đường để đi nếu bạn đang đứng sau một loadbalancer! - Antwan


Tôi đã đăng một nhận xét về câu trả lời đúng một thời gian dài, dài trước đây với một sự điều chỉnh rất quan trọng, nhưng tôi cảm thấy cần phải nêu bật sự điều chỉnh này trong câu trả lời của chính nó. Không có câu trả lời nào trước đây được an toàn khi sử dụng nếu bạn không bảo đảm cài đặt HTTP và mong đợi nội dung người dùng, có biểu mẫu, lưu trữ API hoặc cấu hình bất kỳ trang web, công cụ, ứng dụng hoặc tiện ích nào để nói chuyện với trang web của bạn.

Vấn đề xảy ra khi POST yêu cầu được thực hiện cho máy chủ của bạn. Nếu máy chủ phản ứng với một đồng bằng 30x chuyển hướng nội dung POST sẽ bị mất. Điều gì xảy ra là trình duyệt / khách hàng sẽ nâng cấp yêu cầu lên SSL nhưng hạ cấp các POST đến một GET yêu cầu. Các POST các thông số sẽ bị mất và yêu cầu không chính xác sẽ được thực hiện cho máy chủ của bạn.

Giải pháp rất đơn giản. Bạn cần sử dụng HTTP 1.1 307 chuyển hướng. Điều này được trình bày chi tiết trong RFC 7231 S6.4.7:

  Note: This status code is similar to 302 (Found), except that it
  does not allow changing the request method from POST to GET.  This
  specification defines no equivalent counterpart for 301 (Moved
  Permanently) ([RFC7238], however, defines the status code 308
  (Permanent Redirect) for this purpose).

Giải pháp, được điều chỉnh từ giải pháp được chấp nhận, là sử dụng 307 trong mã chuyển hướng của bạn:

server {
       listen         80;
       server_name    my.domain.com;
       return         307 https://$server_name$request_uri;
}

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000"; 

       [....]
}

6
2018-03-19 20:24



lệnh rất, rất rất hữu ích. cảm ơn! - Denis Matafonov


Tôi quản lý để làm điều đó như thế này:

server {
listen 80;
listen 443 ssl;

server_name domain.tld www.domain.tld;

# global HTTP handler
if ($scheme = http) {
        return 301 https://www.domain.tld$request_uri;
}

# global non-WWW HTTPS handler
if ($http_host = domain.tld){
        return 303 https://www.domain.tld$request_uri;
}
}

https://stackoverflow.com/a/36777526/6076984


4
2018-04-21 18:27



Phiên bản cập nhật, w / o IF: paste.debian.net/plain/899679 - stamster