Flask与Bokeh Server共享端口部署:可行性及实现方案问询
Flask + Bokeh Server 共享8080端口部署方案
当然可行!完全不用让Flask和Bokeh Server各占独立端口,通过反向代理的思路就能让它们共享8080端口,完美适配管控严格的服务器环境。下面给你拆解具体的实现条件和步骤:
核心实现思路
让Flask作为对外的唯一入口(监听8080端口),内部把Bokeh相关的请求转发给本地运行的Bokeh Server(绑定localhost的非公开端口,比如5006)。这样外部只能访问8080端口,符合服务器的管控要求。
必须满足的条件
- 依赖安装:服务器需要安装
flask、requests、gevent、gevent-websocket和bokeh这些Python包,用来支持Flask的代理功能和WebSocket转发(Bokeh实时交互依赖WebSocket)。 - Bokeh Server配置:必须让Bokeh Server只监听
localhost(避免直接对外暴露),同时指定允许WebSocket连接的源为Flask的公开域名/端口,否则Bokeh的实时交互会失败。 - Flask服务器选型:不能用Flask默认的Werkzeug服务器,必须用支持WebSocket的服务器(比如
gevent的WSGIServer),因为要转发Bokeh的WebSocket请求。
具体实现步骤
1. 配置并启动Bokeh Server
在服务器上启动Bokeh Server时,加上这些关键参数:
bokeh serve --allow-websocket-origin=your-public-domain.com:8080 --port=5006 --host=localhost:5006 your_bokeh_app.py
--allow-websocket-origin:指定允许连接Bokeh WebSocket的源,必须是Flask对外的域名+端口(比如你的服务器域名是example.com,就填example.com:8080)。--host=localhost:5006:让Bokeh Server只监听本地请求,外部无法直接访问5006端口。
2. 编写Flask代理代码
创建Flask应用,把/bokeh和/ws开头的请求转发给内部的Bokeh Server:
from flask import Flask, request, Response import requests from werkzeug.middleware.proxy_fix import ProxyFix from gevent import pywsgi from geventwebsocket.handler import WebSocketHandler from geventwebsocket import create_connection from urllib.parse import urljoin app = Flask(__name__) # 处理代理头,确保Bokeh能正确识别请求来源 app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1) # 内部Bokeh Server的地址 BOKEH_SERVER_URL = "http://localhost:5006" # 转发普通HTTP请求(比如Bokeh的静态资源、页面) @app.route('/bokeh/<path:path>', methods=['GET', 'POST']) def proxy_bokeh_http(path): target_url = f"{BOKEH_SERVER_URL}/bokeh/{path}" # 转发请求参数和头信息 if request.method == 'GET': resp = requests.get(target_url, params=request.args, headers=request.headers) elif request.method == 'POST': resp = requests.post(target_url, data=request.form, headers=request.headers) # 返回Bokeh的响应内容 return Response(resp.content, status=resp.status_code, headers=dict(resp.headers)) # 转发WebSocket请求(Bokeh实时交互的核心) @app.route('/ws/<path:path>') def proxy_bokeh_ws(path): client_ws = request.environ.get('wsgi.websocket') if not client_ws: return Response('Expected WebSocket request', status=400) # 转换为WebSocket协议的地址 server_ws_url = urljoin(BOKEH_SERVER_URL.replace('http', 'ws'), f'/ws/{path}') server_ws = create_connection(server_ws_url) # 双向转发WebSocket消息 def forward(from_ws, to_ws): while True: msg = from_ws.receive() if msg is None: break to_ws.send(msg) from gevent import spawn spawn(forward, client_ws, server_ws) spawn(forward, server_ws, client_ws) return '' # 你的其他Flask路由可以写在这里 @app.route('/') def home(): return "Hello from Flask! <a href='/bokeh/your_bokeh_app'>View Bokeh App</a>" if __name__ == '__main__': # 用gevent启动支持WebSocket的Flask服务器,监听8080端口 server = pywsgi.WSGIServer(('0.0.0.0', 8080), app, handler_class=WebSocketHandler) server.serve_forever()
3. 验证部署
启动Flask应用后,外部访问http://your-public-domain.com:8080就能看到Flask的主页,点击链接就能访问嵌入的Bokeh应用,所有请求都通过8080端口转发,5006端口完全对外不可见。
额外注意事项
- 服务器防火墙只需开放8080端口,5006端口保持关闭(因为只监听localhost),进一步提升安全性。
- 如果你的服务器有Nginx等反向代理层,也可以让Nginx直接把Bokeh请求转发给内部的Bokeh Server,Flask和Nginx共享8080端口,但上面的方案是纯Python实现,不需要额外的Web服务器。
内容的提问来源于stack exchange,提问作者Russell Burdt
相关产品推荐
相关产品推荐

