This issue is also opened on shinyxproxy’sgithub: https://github.com/openanalytics/shinyproxy/issues/362
Context
Hi,
We are using shiny proxy behind a reverse proxy as displayed in the following chart. All of this is deployed over Kubernetes.
flowchart LR
User--connect to-->Reverse-proxy;
Reverse-proxy--redirect-->app1[Some Shiny App];
Reverse-proxy--redirect-->ShinyProxy;
ShinyProxy--manage sessions-->app2[Another App];
We are experiencing issues with our WebSocket when deploying our shinyapp using shinyproxy. The WebSocket is instantiated once and does not reconnect afterward. In other words, after a few minutes, we got the gray layer appears over the app indicating that the connection is lost.
Two addtional informations:
- The heartbeat still works fine.
- In the first branch scenario i.e. without shinyproxy, the WebSocket reconnects normally. Both use the same nginx configuration.
First, we thought that it could be duet to a timeout settings but we cannot find any fitting the time.
Do you have any idea, please?
Thankfully,
VL
Expected behavior
WebSocket should reconnect preventing from having an abrupt deconnection
Details
shinyproxy configuration
server:
useForwardHeaders: true
servlet:
context-path: /myexplorerbis
proxy:
title: MyExplorer-Launcher
logo-url: https://devmystat.lorealri.com/home/resources/imgs/logo-mini.jpg
landing-page: /myexplorerbis/app/main
heartbeat-rate: 10000
heartbeat-timeout: 60000
port: 8080
authentication: none
hide-navbar: true
container-backend: kubernetes
kubernetes:
namespace: mystat-myexplorerbis
api-version: v1
image-pull-policy: IfNotPresent
privileged: false
internal-networking: true
container-protocol: http
port: 3838
pod-wait-time: 120000
specs:
- id: main
display-name: MyExplorer Application
container-cmd: ["Rscript", "/srv/app.R"]
container-image: xxxxx/myexplorer:0.6.1.1-shinyproxy
container-memory-request: 3Gi
container-memory-limit: 3Gi
container-cpu-request: 1
container-cpu-limit: 1
port: 3838
stop-on-logout: true
max-lifetime: 120
logging:
file:
name: shinyproxy.log
Nginx server configuration
location /myexplorerbis/ {
set $namespace "mystat-myexplorerbis";
set $ingress_name "application-ingress";
set $service_name "application-svc";
set $service_port "80";
set $location_path "/myexplorerbis/";
set $global_rate_limit_exceeding n;
rewrite_by_lua_block {
lua_ingress.rewrite({
force_ssl_redirect = false,
ssl_redirect = true,
force_no_ssl_redirect = false,
use_port_in_redirects = false,
global_throttle = { namespace = "", limit = 0, window_size = 0, key = { }, ignored_cidrs = { } },
})
balancer.rewrite()
plugins.run()
}
# be careful with `access_by_lua_block` and `satisfy any` directives as satisfy any
# will always succeed when there's `access_by_lua_block` that does not have any lua code doing `ngx.exit(ngx.DECLINED)`
# other authentication method such as basic auth or external auth useless - all requests will be allowed.
#access_by_lua_block {
#}
header_filter_by_lua_block {
lua_ingress.header()
plugins.run()
}
body_filter_by_lua_block {
plugins.run()
}
log_by_lua_block {
balancer.log()
monitor.call()
plugins.run()
}
port_in_redirect off;
set $balancer_ewma_score -1;
set $proxy_upstream_name "mystat-myexplorerbis-application-svc-80";
set $proxy_host $proxy_upstream_name;
set $pass_access_scheme $scheme;
set $pass_server_port $server_port;
set $best_http_host $http_host;
set $pass_port $pass_server_port;
set $proxy_alternative_upstream_name "";
client_max_body_size 0;
proxy_set_header Host $best_http_host;
# Pass the extracted client certificate to the backend
# Allow websocket connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Request-ID $req_id;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $best_http_host;
proxy_set_header X-Forwarded-Port $pass_port;
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
proxy_set_header X-Scheme $pass_access_scheme;
# Pass the original X-Forwarded-For
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
# mitigate HTTPoxy Vulnerability
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
proxy_set_header Proxy "";
# Custom headers to proxied server
proxy_connect_timeout 5s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
proxy_buffering off;
proxy_buffer_size 4k;
proxy_buffers 4 4k;
proxy_max_temp_file_size 1024m;
proxy_request_buffering on;
proxy_http_version 1.1;
proxy_cookie_domain off;
proxy_cookie_path off;
# In case of errors try the next upstream server before returning an error
proxy_next_upstream error timeout;
proxy_next_upstream_timeout 0;
proxy_next_upstream_tries 3;
proxy_pass http://upstream_balancer;
proxy_redirect off;
}
location = /myexplorerbis/ {
set $namespace "mystat-myexplorerbis";
set $ingress_name "application-ingress";
set $service_name "application-svc";
set $service_port "80";
set $location_path "/myexplorerbis/";
set $global_rate_limit_exceeding n;
rewrite_by_lua_block {
lua_ingress.rewrite({
force_ssl_redirect = false,
ssl_redirect = true,
force_no_ssl_redirect = false,
use_port_in_redirects = false,
global_throttle = { namespace = "", limit = 0, window_size = 0, key = { }, ignored_cidrs = { } },
})
balancer.rewrite()
plugins.run()
}
# be careful with `access_by_lua_block` and `satisfy any` directives as satisfy any
# will always succeed when there's `access_by_lua_block` that does not have any lua code doing `ngx.exit(ngx.DECLINED)`
# other authentication method such as basic auth or external auth useless - all requests will be allowed.
#access_by_lua_block {
#}
header_filter_by_lua_block {
lua_ingress.header()
plugins.run()
}
body_filter_by_lua_block {
plugins.run()
}
log_by_lua_block {
balancer.log()
monitor.call()
plugins.run()
}
port_in_redirect off;
set $balancer_ewma_score -1;
set $proxy_upstream_name "mystat-myexplorerbis-application-svc-80";
set $proxy_host $proxy_upstream_name;
set $pass_access_scheme $scheme;
set $pass_server_port $server_port;
set $best_http_host $http_host;
set $pass_port $pass_server_port;
set $proxy_alternative_upstream_name "";
client_max_body_size 0;
proxy_set_header Host $best_http_host;
# Pass the extracted client certificate to the backend
# Allow websocket connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Request-ID $req_id;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $best_http_host;
proxy_set_header X-Forwarded-Port $pass_port;
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
proxy_set_header X-Scheme $pass_access_scheme;
# Pass the original X-Forwarded-For
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
# mitigate HTTPoxy Vulnerability
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
proxy_set_header Proxy "";
# Custom headers to proxied server
proxy_connect_timeout 5s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
proxy_buffering off;
proxy_buffer_size 4k;
proxy_buffers 4 4k;
proxy_max_temp_file_size 1024m;
proxy_request_buffering on;
proxy_http_version 1.1;
proxy_cookie_domain off;
proxy_cookie_path off;
# In case of errors try the next upstream server before returning an error
proxy_next_upstream error timeout;
proxy_next_upstream_timeout 0;
proxy_next_upstream_tries 3;
proxy_pass http://upstream_balancer;
proxy_redirect off;
}
Specific backend configuration
{
"name": "mystat-myexplorerbis-application-svc-80",
"service": {
"metadata": {
"creationTimestamp": null
},
"spec": {
"ports": [
{
"name": "http",
"protocol": "TCP",
"port": 80,
"targetPort": 8080
}
],
"selector": {
"applabel": "deployment-myexplorerbis"
},
"clusterIP": "X.X.X.X",
"type": "ClusterIP",
"sessionAffinity": "None"
},
"status": {
"loadBalancer": {}
}
},
"port": 80,
"sslPassthrough": false,
"endpoints": [
{
"address": "X.X.X.X",
"port": "8080"
}
],
"sessionAffinityConfig": {
"name": "cookie",
"mode": "persistent",
"cookieSessionAffinity": {
"name": "mystat-myexplorerbis-cookie",
"expires": "172800",
"maxage": "172800",
"locations": {
"nginx-ingress-ingress-nginx-controller.ingress.svc.cluster.local": [
"/myexplorerbis/"
]
}
}
},
"upstreamHashByConfig": {
"upstream-hash-by-subset-size": 3
},
"noServer": false,
"trafficShapingPolicy": {
"weight": 0,
"header": "",
"headerValue": "",
"headerPattern": "",
"cookie": ""
}
}