记一次折腾后台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。

相关推荐
danplus22 分钟前
node发送邮件:如何实现Node.js发信功能?
服务器·node.js·外贸开发信·邮件群发·蜂邮edm邮件营销·邮件接口·营销邮件
青稞儿27 分钟前
面试题高频之token无感刷新(vue3+node.js)
vue.js·node.js
BeyondESH36 分钟前
Linux线程同步—竞态条件和互斥锁(C语言)
linux·服务器·c++
wn53138 分钟前
【Go - 类型断言】
服务器·开发语言·后端·golang
hanniuniu1338 分钟前
详细解读,F5服务器负载均衡的技术优势
运维·服务器·负载均衡
PatrickYao04221 小时前
记一次安装discuz时遇到的错误
服务器
小宋10213 小时前
玩转RabbitMQ声明队列交换机、消息转换器
服务器·分布式·rabbitmq
m0_609000423 小时前
向日葵好用吗?4款稳定的远程控制软件推荐。
运维·服务器·网络·人工智能·远程工作
kejijianwen4 小时前
JdbcTemplate常用方法一览AG网页参数绑定与数据寻址实操
服务器·数据库·oracle
Karoku0668 小时前
【网站架构部署与优化】web服务与http协议
linux·运维·服务器·数据库·http·架构