1. ホーム
  2. nginx

Nginxのエラー「The plain HTTP request was sent to HTTPS port」の解決方法。

2022-02-26 02:07:58

転載元 https://blog.yoodb.com/yoodb/article/detail/1527

Nginx HTTP サーバーエラーの報告" 400 Bad Request: The plain HTTP request was sent to HTTPS port "、この記事ではこの問題を解決する方法を説明します。単純にエラーの文字通りの意味からすると、HTTPリクエストがHTTPSポートに送られたためで、NginxがHTTPとHTTPSの両方のリクエストを処理する場合によくあることです。

以下は、Nginxの一般的なSSL設定です(セキュリティのため、当サイトのドメインを使用しています)。この設定ファイルでは、Nginxがポート80と443をリッスンし、すべてのHTTPリクエストをHTTPSにリダイレクトするようにします。

server {
    listen 443;
    server_name blog.yoodb.com;
    charset UTF-8;
    ssl on;
    ssl_certificate /usr/local/nginx/conf/ssl/blog/2539791_blog.yoodb.com.pem;
    ssl_certificate_key /usr/local/nginx/conf/ssl/blog/2539791_blog.yoodb.com.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }
    location / {
        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-Proto https;
        proxy_pass http://172.17.6.114:8082;
    proxy_pass ; }
    location ~*/upload/images/ { 
    expires 1h;
        root /mnt/app/project/files;
    }
    location ~*/dynamic/images/ {
    expires 1h;
        root /mnt/app/project/files;
    }
}

上記の設定は問題ないように見えますが、例えばユーザーが http://blog.yoodb.com を使ってポート 80 のサイトにアクセスしようとリクエストすると、nginx 400 bad request in the browser" というエラーが表示されることになります。 The plain HTTP request was sent to HTTPS port "、以下のような画像例となります。

Nginx がこのエラーを報告するのは、ユーザリクエストが HTTP でアクセスしようとするたびに HTTPS にリダイレクトされるため、Nginx は SSL を使ってやり取りすることを期待していますが、元のリクエスト(ポート 80 で受信)は通常の HTTP リクエストであり、エラーが発生するためです。

一方、ユーザーがhttps://blog.yoodb.com访问网站、上記のようなエラーに遭遇することはありません。また、他のサイトでSSLを使用しない設定にしている場合、NginxはHTTPSを使用しようとしますが、その場合も上記のエラーが発生します。

回避策

上記設定文中の "ssl on;" をコメントアウトまたは修正して "ssl off;" "listen 443;" を "listen 443 ssl" に修正して "listen 80" を追加して、Nginx がHTTPリクエストとHTTPSリクエストを両方処理できるように、次のように設定します。

server {
    listen 80
    listen 443 ssl;
    server_name blog.yoodb.com;
    charset UTF-8;
    ssl_certificate /usr/local/nginx/conf/ssl/blog/2539791_blog.yoodb.com.pem;
    ssl_certificate_key /usr/local/nginx/conf/ssl/blog/2539791_blog.yoodb.com.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }
    location / {
        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-Proto https;
        proxy_pass http://172.17.6.114:8082;
    proxy_pass ; }
    location ~*/upload/images/ { 
        expires 1h;
        root /mnt/app/project/files;
    }
    location ~*/dynamic/images/ {
        expires 1h;
        root /mnt/app/project/files;
    }
}


java redirect https to http問題、httpsでアクセスした場合nginxのproxy_passでhttpのtomcatサービスは正常にアクセスできるが、java redirectはhttpにジャンプし、エラー"が発生する。 400 Bad Request: The plain HTTP request was sent to HTTPS port となります。

回避策

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-Proto https;
proxy_pass http://172.17.6.114:8082;
proxy_redirect http:// https://;


実装フローは、Location http to httpsを完了させるために、nginxの異なる実行フェーズをベースにしています。 

1) proxy_pass 実行前に、まずリクエストヘッドホストをhttpsに設定し、ドメイン+ポートに外部アクセスします。 

2) proxy_pass 実行後、tomcatのresultが応答を返します。 

3) proxy_redirect レスポンス内のロケーションのプロトコル http をエクストラネットアクセス用の https に変更します。 

注意:java リダイレクト リダイレクトは主に tomcat サービスのリクエストヘッドアイテムにアクセスすることで決定され、デフォルトは http プロトコル、ドメイン名はホストアドレスを読み取ることで決定され、デフォルトホストはアクセスポートを含んでいません。