docker / websocket / 群晖 · 2023年6月30日 0

群晖 WebStation 网络门户 docker容器无法使用websocket的问题

WebStation(简称WS)的网络门户可以直接动态映射docker容器的开放端口,该功能可以直接使用http\https双协议开放服务到外网。

不包含websocketweb服务直接配置就能使用了,但是如果dockerweb服务中包含了websocket功能,那么这种方法就不好用了,因为WS套件默认情况下并没有给容器做websocket透传,也就是说网络门户只能代理不包含websocket服务的普通web服务,带有websocket的服务就不行了。

如果不想折腾的话可以直接使用

控制面板 -> 登录门户 -> 高级 -> 反向代理服务 -> 新增一个反向代理规则 -> 自定义标题 -> 新增 -> WebSocket (如下图)

这样的话就会自动添加好websockethttp头,这样这个反向代理就支持websocket接口了

但是该方法有缺陷,配置的时候不能同时使用 http/https 双协议,这样就会导致使用的时候限定了访问网址必须携带协议,并且协议不能写错,一旦写错那就会显示错误无法访问

这样的话就只能返回到WS套件上想办法解决websocket的问题,经过不断查找配置文件终于在 WS套件中 找到了下面这个模版文件 /var/packages/WebStation/target/misc/nginx_service_template.mustache

这个模版文件内容如下

{{#alias}}
location ^~ /{{alias}}/ {
    {{> /usr/syno/share/nginx/acl.mustache}}
    {{> /var/packages/WebStation/target/misc/nginx_web_error_page}}
{{/alias}}

    {{^enable}}
    {{#alias}}
    location ^~ /{{alias}}/ {
        return 404;
    }
    {{/alias}}
    {{^alias}}
    location / {
        return 404;
    }
    {{/alias}}

    {{/enable}}

    {{#enable}}
    {{#alias}}
    {{^uwsgi}}
    {{#root}}
    location = /{{alias}}/ {
        alias    "{{root}}/";
    }
    {{/root}}
    {{/uwsgi}}
    {{/alias}}

    {{#root}}{{^alias}}root{{/alias}}{{#alias}}alias{{/alias}}    "{{root}}{{#alias}}/{{/alias}}"; {{/root}}
    {{#enable_index}}index{{/enable_index}}   {{#index}} {{.}}{{/index}}{{#enable_index}};{{/enable_index}}

    {{#custom_variables}}
    if (${{&.}} = false) {
        set ${{&.}} '';
    }
    {{/custom_variables}}

    {{> @global_rule@ }}

    {{#fastcgi}}
    location ~* \.({{&fastcgi.fastcgi_file_postfix}})$ {
        fastcgi_pass {{fastcgi.fastcgi_pass}};
        {{#fqdn}}fastcgi_param HOST $server_name;{{/fqdn}}

        {{#connect_timeout}}fastcgi_connect_timeout {{.}}s;{{/connect_timeout}}
        {{#read_timeout}}fastcgi_read_timeout {{.}}s;{{/read_timeout}}
        {{#send_timeout}}fastcgi_send_timeout {{.}}s;{{/send_timeout}}

        {{#fastcgi.fastcgi_directive}}
        {{directive}} {{&value}};
        {{/fastcgi.fastcgi_directive}}

        {{> @fastcgi_rule@ }}

        {{#managed_by_docker}} 
        fastcgi_split_path_info ^(.+\.php)(.*)$;
        set $filename "index.php";
        if ( $fastcgi_script_name ~ "^{{#alias}}/{{.}}{{/alias}}/(.*)$" ) {
            set $filename $1;
        }
        fastcgi_param SCRIPT_FILENAME {{#chroot}}{{.}}/{{/chroot}}$filename;
        fastcgi_param PATH_INFO       $fastcgi_path_info;
        fastcgi_param PATH_TRANSLATED $fastcgi_path_info;
        {{/managed_by_docker}}

        include /usr/local/etc/nginx/conf.d/{{service_id}}/fastcgi.conf*;
    }
    {{/fastcgi}}

    {{#uwsgi}}
    location {{#alias}}/{{alias}}{{/alias}}/ {
        {{#alias}}rewrite /{{.}}/(.*) /$1  break;{{/alias}}
        uwsgi_pass {{uwsgi.uwsgi_pass}};
        {{#fqdn}}uwsgi_param HOST $server_name;{{/fqdn}}

        {{#connect_timeout}}uwsgi_connect_timeout {{.}}s;{{/connect_timeout}}
        {{#read_timeout}}uwsgi_read_timeout {{.}}s;{{/read_timeout}}
        {{#send_timeout}}uwsgi_send_timeout {{.}}s;{{/send_timeout}}

        {{#uwsgi.uwsgi_directive}}
        {{directive}} {{&value}};
        {{/uwsgi.uwsgi_directive}}

        {{> @uwsgi_rule@ }}

        include /usr/local/etc/nginx/conf.d/{{service_id}}/uwsgi.conf*;
    }
    {{/uwsgi}}

    {{#proxy}}
    {{#proxy.resolver}}
    include conf.d/.resolve.conf*;
    {{/proxy.resolver}}

    location ~ {{#alias}}/{{alias}}{{/alias}}/{{#use_slash}}(.*)${{/use_slash}} {
        {{#pure_proxy}}{{#alias}}rewrite /{{.}}/(.*) /$1  break;{{/alias}}{{/pure_proxy}}
        {{#connect_timeout}}proxy_connect_timeout {{.}}s;{{/connect_timeout}}
        {{#read_timeout}}proxy_read_timeout {{.}}s;{{/read_timeout}}
        {{#send_timeout}}proxy_send_timeout {{.}}s;{{/send_timeout}}

        proxy_pass {{proxy.proxy_pass}}{{#use_slash}}$1{{/use_slash}};
        {{#proxy.proxy_directive}}
        {{directive}} {{&value}};
        {{/proxy.proxy_directive}}

        {{> @proxy_rule }}

        include /usr/local/etc/nginx/conf.d/{{service_id}}/proxy.conf*;
    }
    {{/proxy}}

    include /usr/local/etc/nginx/conf.d/{{service_id}}/user.conf*;
    {{/enable}}
{{#alias}}
}
{{/alias}}
{{> @universal_rule@ }}

这个模版实际上就是一个mustache语法的nginx配置文件,根据不同的服务类型,启用预先定义好的nginx配置,然后替换变量生成新的nginx配置

在 文件最后的 {{#proxy}} 段定义的就是对应的docker web网页门户使用的nginx配置,其中有两行include内容如下

这行是用户自定义location下的proxy配置

include /usr/local/etc/nginx/conf.d/{{service_id}}/proxy.conf*;

这样是用户自定义的任意配置

include /usr/local/etc/nginx/conf.d/{{service_id}}/user.conf*;

我联系了技术支持,给我的回复就是自己手动去创建这个文件 /usr/local/etc/nginx/conf.d/{{service_id}}/proxy.conf

很明显这个功能是提前设计好的,只不过是个未完成的功能,没有相应的ui界面可以配置,想要用的话就自己手动创建这个文件,手写需要的配置,然后重启对应的docker容器。

为了防止手动修改出错 我写了一个脚本 选择一下就可以直接让websocket可以正常使用了

curl https://git.js-css.com/nap/synology-scripts/raw/branch/master/enable-web-station-websocket.sh | bash

希望官方赶快把这个功能给完善好,这样就不需要每次套件升级,或者容器升级导致需要重新再次手动修改