nginx 400「プレーンHTTPリクエストがHTTPSポートに送信されました」エラーの処理


115

乗客/ nginxの背後でSinatraアプリを実行しています。httpとhttpsの両方の呼び出しに応答できるようにしようとしています。問題は、両方がサーバーブロックで定義されている場合、https呼び出しは正常に応答しますが、httpは400「プレーンなHTTPリクエストがHTTPSポートに送信されました」エラーを生成します。これは静的ページ用なので、シナトラはこれとは何の関係もないと思います。これを修正する方法に関するアイデアはありますか?

サーバーブロックは次のとおりです。

server {
        listen 80;
        listen 443  ssl;
        server_name localhost;
        root /home/myhome/app/public;
        passenger_enabled on;

        ssl on;
        ssl_certificate      /opt/nginx/ssl_keys/ssl.crt;
        ssl_certificate_key  /opt/nginx/ssl_keys/ssl.key;
        ssl_protocols        SSLv3 TLSv1;
        ssl_ciphers          HIGH:!aNULL:!MD5;

        location /static {
            root  /home/myhome/app/public;
            index  index.html index.htm index.php;
        }

        error_page 404 /404.html;

        # redirect server error pages to the static page /50x.html
        error_page 500 /500.html;

        access_log /home/myhome/app/logs/access.log;
        error_log /home/myhome/app/logs/error.log;
}

私の場合、ブラウザのURLが機能my.example.com:443しませんでした。代わりに動作するように変更しhttps://my.example.comます。奇妙なことに、Apacheでこの問題が発生したことはありません。
セバスチャン

1
ssl on;SSLを介してすべてのコンテンツを提供するようにNGINXに指示します。listen 443;たとえばlisten 443 ssl;、サーバーがhttpトラフィックとhttpsトラフィックの両方を配信する場合は、末尾に「ssl」フラグを使用し、ssl on;ディレクティブを削除します。
Stphane

回答:


195

私は同様の問題に遭遇しました。1つのサーバーで動作し、同じNginx構成の別のサーバーでは動作しません。ここでイゴールが答える解決策を見つけましたhttp://forum.nginx.org/read.php?2,1612,1627#msg-1627

はい。または、SSLサーバーと非SSLサーバーを1つのサーバーに結合することもできます。

server {
  listen 80;
  listen 443 default ssl;

  # ssl on   - remember to comment this out

}

rapam iosifによると、必ず含めてくださいssl off;
aceofspades

20
行を削除するだけで済みますssl on;(sslを追加する必要はありません)。また、私はどのNginxバージョンを覚えていないのでdefaultlisten 443オンラインで使用する必要はもうありません。したがって、OP構成は問題なく、削除するだけssl onで動作します。
laurent

@bobojamは、私の回答からの説明を自由に含めて、あなたの説明がより完全になるようにしてください。OPの作者にあなたの答えを受け入れるように頼んだ。
Alexander Azarov

2
コメントすることで、SSLの目的をどのように解決しssl onますか。以下の@ MichaelJ.Evansの回答は、はるかに優れたソリューションです。
Neel

1
複数のconfファイルで動作しないようです。2つの重複するデフォルトがあると言います。アレクサンダーのソリューションを使用します。
Ryall

39

上記の回答は、接続セキュリティに関係なく、http経由でのページの提供を許可するために「is this connection HTTPS」テストをオーバーライドするという点で正しくありません。

NGINX固有のhttp 4xxエラーコードのエラーページを使用してクライアントをリダイレクトし、同じリクエストをhttpsに再試行する安全な回答。(ここで概説しています/server/338700/redirect-http-mydomain-com12345-to-https-mydomain-com12345-in-nginx

OPは以下を使用する必要があります。

server {
  listen        12345;
  server_name   php.myadmin.com;

  root         /var/www/php;

  ssl           on;

  # If they come here using HTTP, bounce them to the correct scheme
  error_page 497 https://$host:$server_port$request_uri;

  [....]
}

1
おそらく$ hostではなく$ server_nameが必要です。おそらくserver_nameは、SSL証明書が認証するCNに設定されています。そうすれば、ユーザーがIPまたはlocalhost経由でアクセスした場合、ユーザーは怖い画面を表示しません。
ジョージ

私はGitLabのローカルインストールにこれを実装しようとしましたが、カスタムNGINX設定をGitLabサーバーブロックメソッドに挿入することでnginx['custom_gitlab_server_config'] = "error_page 497 https://$host:$server_port$request_uri;"うまくいった
Aaron C

17

エラーはそれをすべて実際に言います。設定はNginxにポート80(HTTP)でリッスンし、SSLを使用するように指示します。ブラウザでを指定するとhttp://localhost、HTTP経由で接続しようとします。NginxはSSLを想定しているため、エラーが表示されます。

回避策は非常に簡単です。次の2つのserverセクションが必要です。

server {
  listen 80;

  // other directives...
}

server {
  listen 443;

  ssl on;
  // SSL directives...

  // other directives...
}

7
実際には2つのサーバーセクションは必要ありません。「ssl on」行を削除し、@ bobojamの回答に従ってリッスン行を変更します。
toxaq 2012

12

私はまったく同じ問題を抱えていました、あなたの例と同じような構成があり、行を削除することでそれを機能させました:

ssl on;

ドキュメントを引用するには:

HTTPサーバーとHTTPSサーバーが等しい場合、ディレクティブ「ssl on」を削除し、*:443ポートのsslパラメーターを追加することで、HTTP要求とHTTPS要求の両方を処理する単一サーバーを構成できます。


1
docへのリンクがある可能性がありますか?
Adam Parkin

12

ステータスコードに関するウィキペディアの記事によると。HTTPトラフィックがhttpsポートに送信されると、nginxにはカスタムエラーコードがあります(エラーコード497)

また、error_pageのnginxドキュメントによれば、特定のエラーに対して表示されるURIを定義できます。
したがって、エラーコード497が発生したときにクライアントが送信されるURIを作成できます。

nginx.conf

#lets assume your IP address is 89.89.89.89 and also 
#that you want nginx to listen on port 7000 and your app is running on port 3000

server {
    listen 7000 ssl;
 
    ssl_certificate /path/to/ssl_certificate.cer;
    ssl_certificate_key /path/to/ssl_certificate_key.key;
    ssl_client_certificate /path/to/ssl_client_certificate.cer;

    error_page 497 301 =307 https://89.89.89.89:7000$request_uri;

    location / {
        proxy_pass http://89.89.89.89:3000/;

        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Protocol $scheme;
    }
}

ただし、クライアントがGET以外のメソッドを介してリクエストを行う場合、そのリクエストはGETに変換されます。したがって、クライアントが経由してきたリクエストメソッドを保存するには、error_pageのnginxドキュメントに示されているように、エラー処理リダイレクトを使用します

そして、それが301 =307リダイレクトを使用する理由です。

ここに示すnginx.confファイルを使用すると、httpとhttpsを同じポートでリッスンできます


これは私にとってはうまくいきます-error_page 497 301 = 307 89.89.89.89:7000$request_uri ;
ウガリソフト

7

以下は、ipv6をサポートする同じ構成ブロックでHTTPHTTPSを構成する例です。設定はUbuntu ServerNGINX / 1.4.6でテストされていますが、これはすべてのサーバーで動作するはずです。

server {
    # support http and ipv6
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    # support https and ipv6
    listen 443 default_server ssl;
    listen [::]:443 ipv6only=on default_server ssl;

    # path to web directory
    root /path/to/example.com;
    index index.html index.htm;

    # domain or subdomain
    server_name example.com www.example.com;

    # ssl certificate
    ssl_certificate /path/to/certs/example_com-bundle.crt;
    ssl_certificate_key /path/to/certs/example_com.key;

    ssl_session_timeout 5m;

    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
    ssl_prefer_server_ciphers on;
}

エラーのssl on原因となる可能性のあるものは含めないで400ください。上記の設定は動作するはずです

http://example.com

http://www.example.com

https://example.com

https://www.example.com

お役に立てれば!



4

実際には、次の方法でこれを行うことができます。

ssl off; 

これにより、nginxvhostsの使用に関する私の問題が解決しました。これで、SSLとプレーンHTTPの両方を使用できるようになりました。組み合わせたポートでも機能します。


nginx / 1.6.3で動作します:)
djthoms
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.