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
7 年 2 周 以前
嗯。因为接口要求,以后 https 是标配了。
7 年 2 周 以前
网络劫持太厉害了。
7 年 2 周 以前
好文,感谢王皓分享,尤其是这个方法太给力了,赞啊
6 年 11 个月 以前
我碰到了一切问题,发到这里 https://talk.ninghao.net/t/topic/6512
6 年 6 个月 以前