Apache反向代理连接Docker容器内WebSocket服务器故障排查求助
Apache反向代理Docker容器内WebSocket服务器连接失败排查方案
问题场景
- WebSocket服务器部署在Docker容器内,监听带动态后缀的路径(如
/ws/chat/1694406657943/) - 配置Apache作为反向代理,将WebSocket请求转发至容器内服务器
- 尝试连接
ws://abc.com/ws/chat/1694406657943/时,出现“WebSocket connection failed”错误
已验证操作
- Docker容器内WebSocket服务器运行正常,可处理指定路径的连接请求
- Apache错误日志无相关报错或警告
- Docker容器端口已正确暴露至宿主机
- 直接访问宿主机上的WebSocket服务器可正常建立连接
当前Apache配置
<VirtualHost *:80> # The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName # specifies what hostname must appear in the request's Host: header to # match this virtual host. For the default virtual host (this file) this # value is not decisive as it is used as a last resort host regardless. # However, you must set it for any further virtual host explicitly. #ServerName www.example.com ServerName abc.com ServerAdmin webmaster@abc.com ProxyRequests Off <Proxy *> Require all granted Allow from all </Proxy> ProxyPreserveHost On ProxyPass / http://127.0.0.1:8000/ ProxyPassReverse / http://127.0.0.1:8000/ ProxyPass /ws ws://127.0.0.1:8000/ ProxyPassReverse /ws ws://127.0.0.1:8000/ # error, crit, alert, emerg. # It is also possible to configure the loglevel for particular # modules, e.g. #LogLevel info ssl:warn ErrorLog ${APACHE_LOG_DIR}/abc.com.error.log CustomLog ${APACHE_LOG_DIR}/abc.com.access.log combined # For most configuration files from conf-available/, which are # enabled or disabled at a global level, it is possible to # include a line for only one particular virtual host. For example the # following line enables the CGI configuration for this host only # after it has been globally disabled with "a2disconf". #Include conf-available/serve-cgi-bin.conf </VirtualHost>
报错截图

排查与解决步骤
1. 启用Apache必要模块
WebSocket反向代理依赖proxy_wstunnel模块,执行以下命令启用并重启Apache:
a2enmod proxy proxy_http proxy_wstunnel systemctl restart apache2
2. 修正代理规则顺序与路径匹配
当前配置中ProxyPass / http://127.0.0.1:8000/会优先匹配所有请求,导致/ws开头的WebSocket请求无法触发专门的代理规则。调整规则顺序,将更具体的WebSocket代理放在前面,并保证路径末尾斜杠一致:
<VirtualHost *:80> ServerName abc.com ServerAdmin webmaster@abc.com ProxyRequests Off <Proxy *> Require all granted </Proxy> ProxyPreserveHost On # 优先处理WebSocket请求,保持路径末尾斜杠一致 ProxyPass /ws/ ws://127.0.0.1:8000/ws/ ProxyPassReverse /ws/ ws://127.0.0.1:8000/ws/ # 处理其余HTTP请求 ProxyPass / http://127.0.0.1:8000/ ProxyPassReverse / http://127.0.0.1:8000/ ErrorLog ${APACHE_LOG_DIR}/abc.com.error.log CustomLog ${APACHE_LOG_DIR}/abc.com.access.log combined </VirtualHost>
3. 保留WebSocket握手请求头
添加配置确保Apache不修改WebSocket握手所需的Upgrade和Connection请求头:
ProxyPass /ws/ ws://127.0.0.1:8000/ws/ ProxyPassReverse /ws/ ws://127.0.0.1:8000/ws/ # 强制保留WebSocket握手请求头 RequestHeader set Upgrade %{HTTP:Upgrade}e env=HTTP_UPGRADE RequestHeader set Connection "upgrade" env=HTTP_UPGRADE
4. 启用详细日志排查
调整Apache日志级别,获取请求转发的详细信息:
LogLevel info proxy:debug
重启Apache后,查看abc.com.access.log和abc.com.error.log,确认WebSocket请求是否正确转发至容器内服务器。
5. 再次验证Docker端口映射
检查容器端口映射是否正确,确保宿主机8000端口映射到容器内WebSocket服务器的监听端口:
docker ps
查看目标容器的PORTS列,确认存在类似0.0.0.0:8000->[容器内端口]/tcp的映射规则。
内容的提问来源于stack exchange,提问作者Shamith Wimukthi
相关产品推荐
相关产品推荐

