NoVNC 的网页端涉及到两个地址,分别是前端网页所处的 /
,以及用于传输数据的 WebSocket 连接 /websockify
。用 Nginx 反向代理 NoVNC 服务需要分别处理这两个地址。
将 NoVNC 绑定在 /
将 NoVNC 绑定在根目录非常简单,不需要单独处理 ws 连接,直接将 proxy_pass
设置为 NoVNC 的端口即可并为 ws 连接转发升级连接的请求头即可:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
location / {
proxy_pass http://localhost:7900/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
将 NoVNC 绑定在其他任意路径上
因为 /websockify
和其他资源处在不同的路径上,并且这项配置是写在 NoVNC 配置里的(而不是根据前端网页的位置自动解析的),因此需要对这个路径做一些特殊处理。下面以将 NoVNC 绑定到 /application
为例介绍几种不同的处理方式:
1. 修改 NoVNC 的配置
你可以在界面左侧的配置中点击齿轮-Advanced-WebSocket,点击 Path 输入框将 ws 连接路径修改为 /application/websockify/
(结尾的斜线是必要的)。但是这种方式每次打开都需要修改。
你也可以把 path=/application/websockify/
放在 URL 的查询参数列表里,并让浏览器帮你记住。
2. 将 /websockify 单独绑定
这个方法比较直观,直接添加一个 location /websockify
(结尾无斜线),并仿照上述绑定规则填上即可。缺点是该方法会额外占用一个 /websockify
路径,并且不可修改。详细配置如下:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
location /application/ { # slash is required
proxy_pass http://localhost:7900/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location /websockify { # no slash
proxy_pass http://localhost:7900/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
3. 用一些 workaround 将/websockify 绑在目标路径上
前面提到可以通过将 path=/application/websockify/
放在 URL 的查询参数列表里实现配置 NoVNC 的 ws 连接,我尝试使用 Nginx 的 rewrite 将该查询自动补全到 URL 的后面,这样对前端和用户来说都是无感的。但是无论我怎么尝试,在后台都能看到参数列表是被成功 rewritten 的,但是 NoVNC 就是识别不到,这就很奇怪,按理 NoVNC 应该是拿不到原始请求的,它无法通过原始请求判断参数列表,其中的原因有点搞不清楚。我的处理方式是在 rewrite 语句最后加上 redirect
flag,让浏览器显示请求被跳转到了包含查询列表的链接,这样一来就跟替用户在地址栏中填入 path 没有区别了,实际用起来也蛮爽的。代码如下:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
location /application/ { # slash is required
proxy_pass http://localhost:7900/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location /application/websockify/ { # if here has trailing slash, then rewrite sentence must have one
proxy_pass http://localhost:7900/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location /application-bot/ {
rewrite ^/application-bot/(.*)$ /application/$1?path=application/websockify/ redirect;
proxy_pass http://localhost:7900/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
这样当用户访问 /application-bot
的时候就会自动跳转到 /application/$1?path=application/websockify/
了。