记一次折腾后台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文件类似如下:
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}/default
    ServerName draw-and-guess.xxx.yyy.com
	<Directory ${APACHE_DOCUMENT_ROOT}/default>
		AllowOverride all
	</Directory>
</VirtualHost>
  • 用vue写了个前端,用js写了个后端,前后端websocket逻辑分别为:
js 复制代码
//前端
...
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模块:

shell 复制代码
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

conf 复制代码
<VirtualHost *:443>
    ProxyPass /socket.io ws://127.0.0.1:2345/socket.io
    ProxyPassReverse /socket.io ws://127.0.0.1:2345/socket.io
    DocumentRoot ${APACHE_DOCUMENT_ROOT}/draw-and-guess/dist
    ServerName draw-and-guess.xxx.yyy.com
	<Directory ${APACHE_DOCUMENT_ROOT}/draw-and-guess/dist>
		AllowOverride all
	</Directory>
</VirtualHost>

其中的ProxyPass 和ProxyPassReverse用来转发。

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

log 复制代码
[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。

相关推荐
碎梦归途1 小时前
思科网络设备配置命令大全,涵盖从交换机到路由器的核心配置命令
linux·运维·服务器·网络·网络协议·路由器·交换机
七维大脑虚拟机1 小时前
飞牛NAS公网IPv6+DDNS远程访问零延迟教程
运维·服务器·网络
小天源1 小时前
nginx在centos7上热升级步骤
linux·服务器·nginx
宴之敖者、3 小时前
Linux——\r,\n和缓冲区
linux·运维·服务器
LuDvei4 小时前
LINUX错误提示函数
linux·运维·服务器
未来可期LJ4 小时前
【Linux 系统】进程间的通信方式
linux·服务器
心理之旅4 小时前
高校文献检索系统
运维·服务器·容器
Lenyiin4 小时前
Linux 基础IO
java·linux·服务器
The Chosen One9854 小时前
【Linux】深入理解Linux进程(一):PCB结构、Fork创建与状态切换详解
linux·运维·服务器
2501_927773075 小时前
uboot挂载
linux·运维·服务器