🦄 2024 独立开发者训练营,一起创业!(早鸟优惠在1天后结束)查看介绍 / 立即报名 →

NGINX 对我说:“The plain HTTP request was sent to HTTPS port”

NGINX 对我说 “The plain HTTP request was sent to HTTPS port”,折腾了 8 小时我才明白他的意思。记录一段折腾经历,证明小恶魔都藏在细节里。最近在做给小程序添加应用后台的课程。小程序访问后端服务接口的时候,要保证接口可以通过互联网访问。我用 SSH 在本地跟我的一台服务器之间打了一个通道,访问接口主机名的时候,让服务器把请求转发给我的在本地开发环境上运行的应用。在《互联网访问本地开发环境》里面介绍了这个方法。

在我的服务器上给 NGINX 添加一个配置:

upstream wpdev {
  server 127.0.0.1:7689;
}

server {
  listen       443 ssl;
  server_name  wp-dev.ninghao.net;
  ssl          on;
  index        index.html;

  ssl_certificate           /etc/nginx/ssl/wp-dev.ninghao.net/214318278430706.pem;
  ssl_certificate_key       /etc/nginx/ssl/wp-dev.ninghao.net/214318278430706.key;
  ssl_session_timeout       5m;
  ssl_protocols             TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers               AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
  ssl_prefer_server_ciphers on;

  location / {
   proxy_set_header  X-Real-IP  $remote_addr;
   proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header  Host $http_host;
   proxy_redirect    off;
   expires           off;
   sendfile          off;
   proxy_pass        http://wpdev;
  }
}

然后在本地,用 SSH 打个通道:

ssh -vnNT -R 7689:192.168.50.5:443 phoenix@101.37.27.240 -p 3033

192.168.50.5 是我本地开发环境用的虚拟机的 IP 地址。7689 是服务器上的端口,443 是我本地开发环境虚拟机上的端口。完美解决了调试小程序后端应用接口的环境。很开心地用了一段时间。直到昨天下午五点,调试时发现后端接口没有反应。于是痛苦地折腾开始了。

没反应是因为通道断开了,原因不详,可能是自己的网络问题。没事,再执行一下打通道的命令就行了,不过发现了调试错误信息:

debug1: remote forward failure for: listen 7689, connect 192.168.50.5:443

每次看到 failure 头就大一圈圈。一轮搜索 ~~~   找到了解决的方法。原因是未知原因让 SSH 断开,服务器那边可能没收到信号,他可能在想,我靠,刚才那小子上哪去了,我在这等一会儿他吧。于是服务器那里一直还开着通道端口,等着连接呢。再次尝试去连接这个端口的时候,就会被服务器拒绝,因为他一直在等之前跟他连接的那个人。

所以得杀死(kill)服务器等待这条心。做这件事之前,先得查查看他在那里等谁呢:

sudo netstat -plant | grep 7689

7689 是通道的服务器那头用的端口号。看看服务器在这个端口等着谁。发现:

tcp        0      0 127.0.0.1:7689          0.0.0.0:*               LISTEN      29174/sshd: phoenix 
tcp      516      0 127.0.0.1:7689          127.0.0.1:54812         CLOSE_WAIT  29174/sshd: phoenix

哦,进程的 ID 号是 29174,杀死它:

sudo kill -9 29174

再次打个通道,成功! 不过这回恶魔真的来了。

在小程序里面请求服务接口的时候,返回 400 状态码,表示 Bad Request,提示 The plain HTTP request was sent to HTTPS port 。看这提示,意思就是把 HTTP 请求发给 HTTPS 端口了。啊~ 如果当时脑子清醒,我应该能猜到原因。不过 ...

到底是什么原因,一直有效的方法,怎么就一下子不能用了。开始怀疑是服务器那头出了事儿,重启 NGINX,重载 NGINX。是不是配置文件有冲突?打开通道代理配置一通改,请求还是返回 400 。

我又怀疑是开发环境出了问题,我能想到的是这个错误可能就是 HTTP 与 HTTPS 出了什么事了,我就重新配置了本地开发环境用的虚拟机,启用 SSL,禁用 SSL,重新再来一回。是证书出了问题吗?我把在阿里云为主机名签发的 SSL 证书搬到本地用,结果还是一样。

是我的电脑有问题吗?换一台试试,发现之前测试并且配置好的环境,访问的结果是一样的,出现了 Bad Request 。我地个天,这台电脑我可什么都没动过呀。

我又开始怀疑是服务器的事,我决定换一台服务器试试。把所有的配置搬到了一台新的服务器上,打开浏览器,访问网站。小心肝上窜下跳。咣叽 ..  结果还是一样一样地 ..

继续折腾(蒙太奇场景),修改各种配置 ...    不经历折腾,怎能除 BUG!

后来我又再次认真仔细地看了 NGINX 跟我说的这句话:“The plain HTTP request was sent to HTTPS port” 。哦 ~~ 或许 ~~  查看一下服务器上的 NGINX 的错误日志,发现:

2017/11/09 03:27:51 [error] 12379#12379: *18374 connect() failed (111: Connection refused) while connecting to upstream, client: 113.128.79.22, server: wp-dev.ninghao.net, request: "GET /favicon.ico HTTP/2.0", upstream: "http://127.0.0.1:7689/favicon.ico", host: "wp-dev.ninghao.net", referrer: "https://wp-dev.ninghao.net/"

连接失败,连接被拒。请求的是 http://127.0.0.1:7689/favicon.ico ,快看使用的协议,用的是 HTTP,就是这儿的事。打开通道用的 NGINX 配置文件,修改了一下:

location / {
   ...
   proxy_pass        https://wpdev;
}

把之前用的 http://wpdev,修改成了 https://wpdev。重载 NGINX,打通道,测试访问。成功! 就是少用了一个 s 。我现在仍然没明白,为什么之前好好地用了一段时间。

nginx

评论

我对比了之前你写的这篇博文(https://ninghao.net/blog/4452),里面的配置用的是 HTTP 协议啊,并没有使用 HTTPS

嗯。因为接口要求,以后 https 是标配了。

网络劫持太厉害了。

好文,感谢王皓分享,尤其是这个方法太给力了,赞啊

我碰到了一切问题,发到这里 https://talk.ninghao.net/t/topic/6512

微信好友

用微信扫描二维码,
加我好友。

微信公众号

用微信扫描二维码,
订阅宁皓网公众号。

240746680

用 QQ 扫描二维码,
加入宁皓网 QQ 群。

统计

14696
分钟
0
你学会了
0%
完成

社会化网络

关于

微信订阅号

扫描微信二维码关注宁皓网,每天进步一点