Unable to connect using websocket with forwarded port by an app in the workspace
Hi,
I have an application that run an HTTP server with websocket connexions.
When I launch the app in the workspace Coder create forwarded port as expected but when I try to connect to the application the ws connexions are refused (see image).
I tried the same thing with codespaces (to test if it was my app or Coder) and it works as expected.
Do you know if I had to do a special configuration to enable the websocket connection from a forwarded port?
Thanks

26 Replies
@Stéphane is it possible to get the detail of that specific request that fails?
also, are you running any reverse proxy or load balancer in front of Coder that might be causing this somehow?
Coder is deployed on a kubernetes cluster with Helm (ingress nginx).
Here the HTML page that use websocket to do the connexion, the websocket part begining at the line 2023:
and the original source file (the one attched is from my browser "view source" ;)): https://github.com/javelit/javelit/blob/0c6e9b7f08b88fa2de6dfcd01b9ac50512c72b90/src/main/resources/index.html.mustache#L641
GitHub
javelit/src/main/resources/index.html.mustache at 0c6e9b7f08b88fa2d...
The simplest way to build data apps and webapps in Java. Inspired by Streamlit. - javelit/javelit
oh okay, @Stéphane I get it, the code assumes that the app is runnign on the root of the domain, rather than being on a sub-path, so the request makes it to Coder and Coder refuses that connection because it's not aware of that endpoint
are you able to issue a wildcard certificate on the Coder subdomain at all?
e.g
*.workshop.labdevrel.ovhThanks for the answer
the fact is that we are using cert-manager to generate the SSl certificate and we are using HTTP01 for the cert challenge
But the problem is:
"Wildcard certificates are not supported with HTTP01 validation and require DNS01."
So i'm checking if we can use DNS01 in our infra 😅
@Phorcys where (in the code) did you see that the ws connexion uses a subdomain?
In the code I see this:
ws = new WebSocket(${protocol}//${host}/_/ws); but no use of subdomain, right?
The forwarded port is: https://workshop.labdevrel.ovh/%40stephane/sopra-spt-01.main/apps/code-server/proxy/8080/ so for us only the domain workshop.labdevrel.ovh is used by the previous code line.
One difference with Code Spaces URL is that the Code Spaces URL has no sub path (https://stunning-space-bassoon-5v5gwg6rjp6f7rjj-8080.app.github.dev/), I don't know if it's important.@Stéphane
basically, the issue is that your app is hosted at
https://workshop.labdevrel.ovh/%40stephane/sopra-spt-01.main/apps/code-server/proxy/8080
but the program logic (new WebSocket(`${protocol}//${host}/_/ws`);) here will cause the websocket url to be:
wss://workshop.labdevrel.ovh/_/ws
instead of
wss://workshop.labdevrel.ovh/%40stephane/sopra-spt-01.main/apps/code-server/proxy/8080/_/ws because it assumes that the main app is being served on /
it is, that's the root cause of your issuealso, for what it's worth, i would recommend not using code-server for the proxying but using Coder's built-in port forward

or even better, define a
coder_app resource in the template!
what you need to do is either provision a wildcard *.workshop.labdevrel.ovh certificate to allow Coder to do the same as CodeSpaces in this scenario
OR modify the app to take into account the different path that the app is being served atfrom which version I have the option Listening Ports ? I have not it the menu in my version (v2.25.1+3bf6a00)

you will get it automatically if you enable the wildcard subdomain for Coder
you can also do
CODER_DANGEROUS_ALLOW_PATH_APP_SHARING=true if you can't do wildcard
it is unsafe, but technically not more unsafe than what you're already doing through code-server
path-based sharing is not recommended because it causes the apps to be able to access the Coder authentication cookies, which is why i'm recommending wildcard instead :)If I well understand the
coder_app resource the url attribute must be an available URL but in my case I launch manually the undertow server so at the workspace starting the webserver is not running.
It's just launched sometimes to test some part of code.you can do that still, it's just that the url will only work when the app is running, it's just more friendly because then you'd have a button for your testing app
you can also set a healthcheck so that the button is greyed out when it's not running
I've still the error with this coder_app declaration:
Is it because I set the subdomain to false ?
what error?
oh, the websocket, yeah that's won't fix the issue that is in the app
just recommended to do that instead of code-server proxy
Hey I'm the maintainer of Javelit, thanks for looking at this, I am working on a fix.
Is the proxy passing a header with the url subpath ?
For instance something like X-Forwarded-Prefix ? (there is no standard for this but it's a common value)
Eg:
X-Forwarded-Prefix: /sopra-spt-01.main/apps/code-server/proxy/8080
hey! thanks for joining, it is not passed AFAIK
but it can be if absolutely necessary
usually we expect apps to assume that the websocket path should be relative to the path where the app is served at
but, in the past i've seen it done through a query parameter
e.g a
?path=/base/path that is computed by the template -> https://github.com/uwu/basic-env/blob/59d7e8d9b0328ffa59654eb8de79f200a930fcd6/main.tf#L256thanks, the issue is also impacting other places in the codebase related to page routing and media serving.
- javelit supports pages so url may look like {coder.com_proxy_sub_path}/{javelit_sub_path}
- media urls should have the subpath as prefix (I can't use relative as the user may be in a javelit subpath)
I don't think there is a way to properly infer the subpath in all cases (Streamlit and Gradio were not able to do it either) so I need the subpath explicitely.
In terms of solution:
1. I'm not a fan of the url parameter because if it's not passed or lost then the app is broken, and it'll be confusing.
2. I think the X-Forwarded-Prefix is a better solution, as it means javelit will behave properly automatically, can be served by multiple proxies on different sub_paths transparently, etc...
3. in the meantime, similar to the url parameter, I'll implement passing the subpath manually via command line / server argument when launching javelit
eg with something like
if I understand the code you shared correctly in the coder config it will look like:
(the 8080 port can also be templatized I guess)
yeah, that base path approach is also used by some other apps
X-Forwarded-Path, sure, but that needs a trust mechanism to only allow it from specific hosts
@cyrilou242 if you need a Coder instance with a fresh workspace to do some tests, I can give you an access to my platform 😉
I'm good, writing my own proxy in the e2e test 🙂 the fix should be ready in an hour
Hey @Stéphane you can pass Javelit the subpath it's running on with:
(I'll let you replace with coder.com variables where relevant
${data.coder_workspace.some.variable.name}
This is available in Javelit version 0.73.0
--base-path CLI doc:
I will test ASAP 😉
Big thanks 🫶
nice!
@cyrilou242 amazing, thanks for the work
Everything works as expected on Coder now!
Thanks a lot, you save my back!
Thanks! 🥰