使用https时,我无法让bokeh服务器呈现可视化效果。我有一个类似的堆栈,其中bokeh服务器按预期与http一起工作。另外,我可以为静态bokeh.html文件获得一个https连接。但是,将脚本标记传递到我的template.html不适用于https。
我在运行flask应用程序的gunicorn前面使用nginx作为反向代理。 flask应用程序从特定端口上正在运行的bokeh服务器中提取会话。主管人员监视bokeh服务器进程和Gunicorn / flask进程。
我在以下位置浏览了现有的bokeh文档:
https://bokeh.pydata.org/en/latest/docs/user_guide/server.html#reverse-proxying-with-nginx-and-ssl
我还在SO上浏览了一些类似的问题:
How to configure Nginx with gunicorn and bokeh serve
Bokeh Serve HTTPS instead of HTTP
How to enable SSL/HTTPS on bokeh 0.12.5?
Making script content 'safe' for HTTPS display (Bokeh)
在烧瓶应用程序中,我尝试了组合选项,分别用于flask_app中的relative_urls = True / False和--allow-websocket-origin =“ myIP”/["*"]。
在这一点上,我认为我只是缺少明显的东西,我希望其他人也会看到它。我认为关键是,在提供静态bokeh.html文件或其他内容时,https可以在堆栈中上下移动,但是在尝试嵌入bokeh服务器时会失败。我怀疑我缺少有关如何通过烧瓶进行会话的东西。
谢谢!
以下是我认为的配置和flask.app文件的所有相关部分:
/ etc / nginx / sites-available / flask_settings的内容
upstream gunicorn_flask {
server 127.0.0.1:6000 fail_timeout=0;
}
server {
listen 443 ssl http2 default_server;
server_name ###.###.###.###;
include snippets/self-signed.conf;
include snippets/ssl-params.conf;
access_log /var/log/nginx/https_access.log;
error_log /var/log/nginx/https_error.log;
ssl on;
location / {
proxy_pass http://gunicorn_flask;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header X-Forwarded_Proto $scheme;
proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
proxy_buffering off;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header Host $host:$server_port;
}
}
server {
listen 80;
server_name ###.###.###.###;
return 301 https://$server_name$request_uri;
}
/etc/nginx/snippets/self-signed.conf的内容
ssl_certificate /path/to/my/file.crt;
ssl_certificate_key /path/to/my/file.key;
/etc/nginx/snippets/ssl-params.conf的内容
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000";
ssl_dhparam /etc/ssl/certs/dhparam.pem;
/etc/supervisor/conf.d/bokeh.conf的内容
[program:my_bokeh_viz]
directory=/my/path/to/bokeh/viz
command=/my/path/to/bokeh/bin/bokeh serve --allow-websocket-origin=###.###.###.### --address=127.0.0.1 --port 6001 --use-xheaders /my/path/to/bokeh/viz.py
autostart=true
autorestart=true
stderr_logfile=/var/log/my_bokeh_viz/Bokeh_Flask.err.log
stdout_logfile=/var/log/my_bokeh_viz/Bokeh_Flask.out.log
/etc/supervisor/conf.d/gunicorn.conf的内容
[program:gunicorn_bokeh]
directory=/my/path/to/flask/app
command=/my/path/to/anaconda3/bin/gunicorn my_flask_app:app --bind 127.0.0.1:6000 --pythonpath /my/path/to/flask/app
autostart=true
autorestart=true
stderr_logfile=/var/log/gunicorn_bokeh/Bokeh_Flask.err.log
stdout_logfile=/var/log/gunicorn_bokeh/Bokeh_Flask.out.log
/path/to/my/flask/app.py的内容
--- Relevant section of flask app.py
@app.route('/web/path/to/bokeh/viz', methods = ['GET'])
@login_required
def show_bokeh_viz():
host_url = 'http://127.0.0.1:6001/my_bokeh_viz'
my_session = pull_session(url = host_url)
client_url = 'http://###.###.###.###/web/path/to/bokeh/viz'
my_script = server_session(model = None,
session_id = my_session.id,
url = client_url,
relative_urls = False)
return render_template("embed.html", script = my_script, template = "Flask")
@app.route('/testing', methods = ['GET'])
@login_required
def show_test():
return render_template("stocks.html")
内容:/path/to/my/flask/app/templates/embed.html
<!doctype html>
<html>
<body>
{{ script|safe }}
</body>
</html>
呈现结果的页面来源:
<!doctype html>
<html>
<body>
<script
src="https://###.###.###.###/web/path/to/my/bokeh/viz/autoload.js?bokeh-autoload-element=a4c3a28c-8bab-4e54-8ba8-8423914078aa&bokeh-app-path=/web/path/to/my/bokeh/viz&bokeh-absolute-url=https://###.###.###.###/web/path/to/my/bokeh/viz&bokeh-session-id=2GYRA1MPiBBX0qzlIB5ZEMyWQkV9AD1Br1KdgtZoew5P"
id="a4c3a28c-8bab-4e54-8ba8-8423914078aa"
data-bokeh-model-id=""
data-bokeh-doc-id=""
></script>
</body>
</html>
答案 0 :(得分:0)
我认为有几点。通过创建bokeh会话,您实际上只创建了浏览器调用的脚本来执行bokeh背景。在浏览器中,它将尝试调用您提供的任何内容,而我们需要它调用https://example.com/ .....,以便nginx将bokeh流量发送到bokeh服务器而不是gunicorn服务器。>
我发现的最佳解决方案是在所有bokeh server_session / server_document调用前加上一些前缀,以便nginx可以将它们发送到bokeh服务器而不是flask,然后用nginx去除前缀。我尝试使用bokeh serve --prefix标记,但是在加载静态资产时遇到了一些问题。
@app.route('/web/path/to/bokeh/viz', methods = ['GET'])
@login_required
def show_bokeh_viz():
my_session = pull_session(url = http://localhost:6001/my_bokeh_viz)
# use actual url here
host_url = 'https://example.com/bokeh_stuff/my_bokeh_viz'
my_script = server_session(model = None,
session_id = my_session.id,
url = url,
relative_urls = False)
return render_template("embed.html", script = my_script, template = "Flask")
有关nginx的位:
# All bokeh plots are prefixed with some unique route, in this case 'bokeh_stuff'
# Here we will collect these, strip off the prefix, and send the result to the bokeh server
# Sends https://example.com/bokeh_stuff/sliders ⇒ http://localhost:6001/sliders
location /bokeh_stuff {
rewrite ^/bokeh_stuff/(.*) /$1 break;
proxy_pass http://127.0.0.1:6001;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host:$server_port;
proxy_buffering off;
}
# All traffic other than static and bokeh_stuff goes to the gunicorn server
location / {
# forward application requests to the gunicorn server
proxy_pass http://localhost:6000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
然后在bokeh服务中,您需要添加--allow-websocket-origin=example.com
要测试正在发生的情况,请查看控制台和网络请求以及bokeh服务器的输出(主管日志),并查看它能为您提供什么。您也可以转到example.com/bokeh_stuff,即使您的路由功能仍然存在问题,也应该获取索引页。