当前位置: 首页 > news >正文

记一次折腾后台nodejs服务的经历

前言

之前写了一个基于websocket的你画我猜小游戏,优势在于无广告、不限制参与人数,并在gitee上开源了:https://gitee.com/bychang/draw-and-guess。当时租了一年的云服务器,现在快到期了,所以打算迁移到自己的服务器上。

不过由于自己的服务器用了https、网站服务是部署在docker里的、并且端口不能随便开放,折腾了好半天,终于算是能用了(尽管可能不那么优雅hh)。因此写一篇博客记录一下踩坑历史。

背景

  • 服务器只有两个对外开放的端口,都在2000以上。防火墙会将外部访问服务器7777端口的请求转发到服务器的2345端口,访问6666端口的请求转发到服务器的1999端口。
  • 网站服务用的github上的docker-compose-lamp项目,集成好了apache、php、mysql等环境。
  • 在apache(版本2.4.59)的config那里配置了四级域名转发,主机1999端口映射到容器443端口,conf文件类似如下:
ServerName 172.18.0.5
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/xxx_yyy_com.pem
SSLCertificateKeyFile /etc/apache2/ssl/xxx_yyy_com.key<VirtualHost *:443>DocumentRoot ${APACHE_DOCUMENT_ROOT}/defaultServerName draw-and-guess.xxx.yyy.com<Directory ${APACHE_DOCUMENT_ROOT}/default>AllowOverride all</Directory>
</VirtualHost>
  • 用vue写了个前端,用js写了个后端,前后端websocket逻辑分别为:
//前端
...
import { io } from 'socket.io-client';
...
const SERVER_ADDR = 'https://draw-and-guess.xxx.yyy.com:7777/';
const socket = ref(io(SERVER_ADDR, { transports: ['websocket'] }));
...//后端
var app = require('http').createServer();
var io = require('socket.io')(app);
app.listen(2345,'127.0.0.1')
...

预期效果与现有效果

预期效果:玩家访问https://draw-and-guess.xxx.yyy.com:6666时,会自动和https://draw-and-guess.xxx.yyy.com:7777建立websocket连接,从而可以正常开始游戏。

现有效果:网站可以正常打开,但是建立连接时浏览器控制台报错 WebSocket connection to 'wss://draw-and-guess.xxx.yyy.com:7777/socket.io/?EIO=4&transport=websocket' failed,没有进一步的报错信息。服务器后端js控制台也没有显示报错信息。

尝试1

先确保服务器可以收到消息:nc -lk 2345然后打开网站,发现确实有显示。然后看了一下socket.io官方的排错教https://socket.io/docs/v4/troubleshooting-connection-issues/,说是用curl可以检测一下。测试curl "https://draw-and-guessd.xxx.yyy.com:7777/socket.io/?EIO=4&transport=polling"发现回显是curl: (35) error:0A00010B:SSL routines::wrong version number。应该是服务器端2345没有tls,所以无法连接。

尝试2

那么能不能用http呢?在curl测试curl "http://draw-and-guessd.xxx.yyy.com:7777/socket.io/?EIO=4&transport=polling"是可以连接的,但是浏览器会报错Mixed Content: The page at 'https://draw-and-guess.xxx.yyy.com:6666/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://draw-and-guess.xxx.yyy.com:7777/socket.io/?EIO=4&transport=websocket'. This request has been blocked; this endpoint must be available over WSS.。所以是https场景下不能使用http做websocket了。之前用华为云服务器的时候因为就没弄https,所以http是可以的。

尝试3

那么既然1999端口能提供tls,是否可以也把websocket放在这个端口呢?显然不行,因为docker在做1999->443端口映射的时候是跑了一个docker-proxy程序的,这个端口就被占用了,没法再跑websocket。

尝试4

能否在2345端口再开一个tls服务,然后处理websocket?查了下发现是可以的,只需要启用proxy模块,然后添加转发规则就行了。首先先进入apache的docker,启用proxy和wstunnel模块:

cd /etc/apache2/mods-enabled
ln -s ../mods-available/proxy.load proxy.load
ln -s ../mods-available/proxy.conf proxy.conf
ln -s ../mods-available/proxy_wstunnel.load proxy_wstunnel.load

然后修改config

<VirtualHost *:443>ProxyPass /socket.io ws://127.0.0.1:2345/socket.ioProxyPassReverse /socket.io ws://127.0.0.1:2345/socket.ioDocumentRoot ${APACHE_DOCUMENT_ROOT}/draw-and-guess/distServerName draw-and-guess.xxx.yyy.com<Directory ${APACHE_DOCUMENT_ROOT}/draw-and-guess/dist>AllowOverride all</Directory>
</VirtualHost>

其中的ProxyPass 和ProxyPassReverse用来转发。

结果发现apache错误日志文件报错:

[proxy:error] [pid 298] (111)Connection refused: AH00957: WS: attempt to connect to 127.0.0.1:2345 (127.0.0.1:2345) failed
[proxy_wstunnel:error] [pid 298] [client 192.3.118.133:42940] AH02452: failed to make connection to backend: 127.0.0.1

原来是因为apache跑在docker里,而2345端口是在宿主机监听的,docker里2345没有运行服务。

也没法把宿主机2345和容器2345绑定,这样又回到了docker-proxy的端口占用问题。

尝试5

本来顺理成章地可以在apache的docker里启动node后端,但当时想的是一种更为“优雅”的方法,就是再启动一个nodejs的docker和apache联动。试了下似乎不管怎么写command,启动以后都自己退了。折腾半天docker compose,略过不表。

尝试6

最后祭出大杀器,直接在compose配置文件把宿主机的nodejs映射到apache容器里,然后在容器内部运行js后端。为了保证控制台退出可用,研究了下screen里启动docker后怎么在不退出docker的情况下退出screen,无果。也研究了下docker exec -d xxxx xxx.sh来试图运行一个后台执行后端程序的docker,也失败了。

最后直接在宿主机开一个screen,里面进入apache docker,手动启动后端,再直接鼠标关了终端才圆满解决(至少服务可以用了)hhh。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • shopee虾皮 java后端 一面面经 整体感觉不难
  • Android TabLayout的简单用法
  • 【JavaEE】Bean的作用域和生命周期
  • AI/机器学习(计算机视觉/NLP)方向面试复习3
  • 如何通过一条SQL变更多个分库分表?
  • iptables 限制端口仅特定IP访问。
  • Apache DolphinScheduler 3.2.2 版本正式发布!
  • 一文解析:代理IP的五大优势
  • 【C#】获取DICOM图像像素的像素值
  • 【CTFWP】ctfshow-web42
  • Spark实时(一):StructuredStreaming 介绍
  • 推荐系统三十六式学习笔记:工程篇.常见架构25|Netflix个性化推荐架构
  • 【SpringBoot教程:从入门到精通】掌握Springboot开发技巧和窍门(四)-Vue项目配置环境、导航栏
  • MySQL常见指令
  • Python 高阶语法
  • SegmentFault for Android 3.0 发布
  • 03Go 类型总结
  • 2017届校招提前批面试回顾
  • Docker容器管理
  • ES6语法详解(一)
  • Javascript编码规范
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • opencv python Meanshift 和 Camshift
  • PAT A1120
  • Sublime text 3 3103 注册码
  • Webpack 4x 之路 ( 四 )
  • 闭包--闭包作用之保存(一)
  • 编写符合Python风格的对象
  • 京东美团研发面经
  • 经典排序算法及其 Java 实现
  • 离散点最小(凸)包围边界查找
  • 每天10道Java面试题,跟我走,offer有!
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 设计模式走一遍---观察者模式
  • Nginx实现动静分离
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • ​浅谈 Linux 中的 core dump 分析方法
  • #基础#使用Jupyter进行Notebook的转换 .ipynb文件导出为.md文件
  • (11)MATLAB PCA+SVM 人脸识别
  • (NSDate) 时间 (time )比较
  • (独孤九剑)--文件系统
  • (附源码)spring boot校园拼车微信小程序 毕业设计 091617
  • (规划)24届春招和25届暑假实习路线准备规划
  • (五)IO流之ByteArrayInput/OutputStream
  • (一)Dubbo快速入门、介绍、使用
  • (转)winform之ListView
  • (转载)虚函数剖析
  • *上位机的定义
  • .a文件和.so文件
  • .NET Micro Framework 4.2 beta 源码探析
  • .NET 中 GetProcess 相关方法的性能
  • .NET6 命令行启动及发布单个Exe文件
  • .NetCore项目nginx发布
  • .NET中winform传递参数至Url并获得返回值或文件