4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Nginxの「400 The plain HTTP request was sent to HTTPS port」の対処

Last updated at Posted at 2019-03-10

概要

  • Nginxでリバースプロキシなサーバを作った
  • 「https://〜」(443ポート)へのアクセスは正常に処理される
  • 80番ポートがなぜかhttpsなポートとして処理されてしまう
  • 結果的に「400 The plain HTTP request was sent to HTTPS port」が出て困る

前提

  • ${内容}は変数的なものです
  • サーバOS: Ubuntu 18.04.02 LTS
  • Nginx: 1.14.0

したいこと

ドメイン名のみのリンクをクリックされた場合に、ブラウザに関係なくHTTPSなサイトに誘導する

症状

ドメイン名のみのリンクの場合、

  • Chrome (72.0.3626.119(64-bit)) はうまく解釈してくれました
  • Firefox (65.0.1 (64-bit)) はhttpとして解釈され以下の症状が出ました
リクエスト内容 curlレスポンス(*1) requestsレスポンス(*2)
http://${ドメイン名}:80 301 400(*3)
http://${ドメイン名}:443 301 400(*3)
https://${ドメイン名}:80 x 200
https://${ドメイン名}:443 200 200

*1)

request.sh
curl ${リクエスト内容} -k # kオプションで証明書エラーを無視

*2)

request.py
import requests
requests.packages.urllib3.disable_warnings() # 証明書warningを無視
a = requests.get(${リクエスト内容}, verify=False) # verfy=False: 証明書errorを無視

*3)
nginx-bad-request-error.png

対処

とりあえず設定箇所を全文

/etc/nginx/sites-enable/default
server {
    listen 80;
    listen 443 ssl;
    server_name ${domain};

    ssl_certificate      ${キーファイルのパス}/2019.crt.pem;
    ssl_certificate_key  ${キーファイルのパス}/2019.key.pem;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;

    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-NginX-Proxy true;

    location / {
        proxy_pass http://127.0.0.1:8000; # localhostにすると色々ハマる
    }

    error_page 497 /497.html;
    location = /497.html {
        root /var/www/html;
        internal;
    }
}

(※)エラー内容は400で、レスポンスも400だが、実際には497エラーを400にリダイレクト(?)している模様(´・ω・`)
参考: nginx でエラーページ出すなや〜 "400 The plain HTTP request was sent to HTTPS port"
(※)ポート番号はバックで動いてるアプリのポート番号で。

/var/www/html/497.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="ja">
    <head><meta charset="utf-8"></head>
    <body>
        HTTPアクセスはできません。トップページにリダイレクトします。
        <script type="text/javascript">
            setTimeout(function(){ window.location.href = 'https://${ドメイン名}'; }, 100);
        </script>
    </body>
</html>

(※)/var/www/htmlの所有者・グループがwww-dataにする(sudo chown -R www-data:www-data /var/www/html)のを忘れないように

その他

割と場当たり的な対処になってしまいました。
調べていると「ssl onをコメントアウトする」対処が多かったですが今回はうまく動作しませんでした。

挙動から察するに
NginxはマウントしたポートをデフォルトでHTTPSなポートとして解釈してしまってるような気がします。
大元の設定ファイルである/etc/nginx/nginx.confも確認しましたが、それらしい記述はなさそう。
もう一つ謎なのは、SSLが完全に無い状態で80番ポートのみをマウントすると、ローカルからのリクエストは受け付けるのに、リモートからのリクエストは弾かれました。iptablesの設定は確認したのでAppArmorな気もしますが、ちょっとよく分かりません。。
分かるひと教えて下さい(´・ω・`)

4
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?