Skip to content

Conversation

@fcancela
Copy link

@fcancela fcancela commented Jan 22, 2026

Summary

Fix WSL2 + Windows Chrome local dev where WebTransport (QUIC/UDP) to localhost fails, causing a WebSocket fallback.

Problem / symptoms

  • Browser console:
    • Failed to establish a connection to https://localhost:4443/anon: net::ERR_CONNECTION_RESET
    • ... using WebSocket fallback; the user experience may be degraded
  • Visiting http://.../anon shows 400 Connection header did not include 'upgrade' (expected; /anon is not an HTTP endpoint).

Root cause (validated)

  • http://<wsl-ip>:4443/certificate.sha256 worked (HTTP/TCP reachability ok)
  • ws://<wsl-ip>:4443/anon worked (WebSocket/TCP ok)
  • Only WebTransport to https://localhost:4443/... failed (WSL2 localhost forwarding doesn’t reliably support UDP/QUIC)
  • Switching to the WSL VM IP and binding/certifying for it makes WebTransport succeed.

Fix

Dev tooling now:

  • Uses WSL VM IP instead of localhost for the relay URL when in WSL (just web auto / just dev)
  • In WSL only, runs the relay with:
    • --server-bind 0.0.0.0:4443 (QUIC reachable from Windows)
    • --tls-generate localhost,<wsl-ip> (WebTransport upgrades to https://…; cert SAN must match the IP host)
  • Keeps non-WSL behavior unchanged.
  • Runs Vite with --host 0.0.0.0 so Windows can open the dev server via the WSL IP.

Test plan

  • In WSL: just dev
  • Confirm WebTransport connects (no ERR_CONNECTION_RESET, no WebSocket fallback warning)

When running under WSL2, Windows Chrome can't reach QUIC/UDP via localhost forwarding.
Auto-select the WSL IP for the hang demo and override relay bind/cert generation only in WSL.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

Walkthrough

The pull request modifies the justfile to improve web server and relay command functionality. The web task replaces direct URL invocation with "auto" URL resolution that handles both WSL and non-WSL environments. The relay command adds WSL-specific logic that binds the server to 0.0.0.0:4443 and generates TLS certificates using local IP, while preserving existing behavior outside WSL. The web server is configured to bind to 0.0.0.0 with environment-conditional URL resolution for localhost or host IP address.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(dev): make just recipes WSL2-friendly' directly matches the main objective of the PR, which is fixing WSL2-specific issues with dev tooling and WebTransport connectivity.
Description check ✅ Passed The description provides comprehensive context about the WSL2 WebTransport issue, root cause analysis, and the implemented fix, which aligns with the changeset modifications to the justfile.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@justfile`:
- Around line 36-41: The WSL branch sets ip="$(hostname -I | awk '{print $1}')"
then passes it to --tls-generate which can produce an invalid SAN when empty;
add a guard that checks the ip variable before invoking cargo: if ip is empty,
print an error and exit (fast-fail) rather than continuing to run
TOKIO_CONSOLE_BIND=... cargo run --bin moq-relay -- dev/relay.toml ...
--tls-generate "localhost,$ip". Ensure the check lives in the same justfile WSL
block so the variables (ip, TOKIO_CONSOLE_BIND) and the invocation of moq-relay
are only executed when ip is non-empty.
- Around line 269-279: The web recipe currently always appends "--host 0.0.0.0"
which exposes the Vite server to the LAN; change the invocation in the web
recipe (the line that runs: cd js/hang-demo && VITE_RELAY_URL="$url" bun run dev
-- --host 0.0.0.0) to only include "--host 0.0.0.0" when running under WSL
(WSL_DISTRO_NAME present) or when an explicit opt-in flag/env (e.g.,
DEV_HOST_ALL or similar) is set; otherwise omit the --host flag (or use --host
localhost) to keep the server bound to loopback. Ensure the conditional uses the
existing WSL_DISTRO_NAME check or a new opt-in env and updates the command
construction accordingly.

Comment on lines +36 to +41
@if [ -n "${WSL_DISTRO_NAME:-}" ]; then \
ip="$(hostname -I | awk '{print $1}')"; \
TOKIO_CONSOLE_BIND=127.0.0.1:6680 cargo run --bin moq-relay -- dev/relay.toml \
--server-bind "0.0.0.0:4443" \
--tls-generate "localhost,$ip" \
{{args}}; \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add a guard for empty WSL IP detection.

If hostname -I returns nothing, TLS SAN becomes invalid and the relay may fail or generate a bad cert. Consider a fast-fail check.

🛠️ Suggested guard
-		ip="$(hostname -I | awk '{print $1}')"; \
+		ip="$(hostname -I | awk '{print $1}')"; \
+		if [ -z "$ip" ]; then \
+			echo "Error: unable to detect WSL IP" >&2; \
+			exit 1; \
+		fi; \
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@if [ -n "${WSL_DISTRO_NAME:-}" ]; then \
ip="$(hostname -I | awk '{print $1}')"; \
TOKIO_CONSOLE_BIND=127.0.0.1:6680 cargo run --bin moq-relay -- dev/relay.toml \
--server-bind "0.0.0.0:4443" \
--tls-generate "localhost,$ip" \
{{args}}; \
`@if` [ -n "${WSL_DISTRO_NAME:-}" ]; then \
ip="$(hostname -I | awk '{print $1}')"; \
if [ -z "$ip" ]; then \
echo "Error: unable to detect WSL IP" >&2; \
exit 1; \
fi; \
TOKIO_CONSOLE_BIND=127.0.0.1:6680 cargo run --bin moq-relay -- dev/relay.toml \
--server-bind "0.0.0.0:4443" \
--tls-generate "localhost,$ip" \
{{args}}; \
🤖 Prompt for AI Agents
In `@justfile` around lines 36 - 41, The WSL branch sets ip="$(hostname -I | awk
'{print $1}')" then passes it to --tls-generate which can produce an invalid SAN
when empty; add a guard that checks the ip variable before invoking cargo: if ip
is empty, print an error and exit (fast-fail) rather than continuing to run
TOKIO_CONSOLE_BIND=... cargo run --bin moq-relay -- dev/relay.toml ...
--tls-generate "localhost,$ip". Ensure the check lives in the same justfile WSL
block so the variables (ip, TOKIO_CONSOLE_BIND) and the invocation of moq-relay
are only executed when ip is non-empty.

Comment on lines +269 to +279
web url="auto":
@url="{{url}}"; \
if [ "$url" = "auto" ]; then \
if [ -n "${WSL_DISTRO_NAME:-}" ]; then \
ip="$(hostname -I | awk '{print $1}')"; \
url="http://$ip:4443/anon"; \
else \
url="http://localhost:4443/anon"; \
fi; \
fi; \
cd js/hang-demo && VITE_RELAY_URL="$url" bun run dev -- --host 0.0.0.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid binding Vite to all interfaces outside WSL.

--host 0.0.0.0 on non-WSL exposes the dev server to the LAN by default. Consider limiting it to WSL only (or making it opt-in) to keep the previous security posture.

🔒 Suggested conditional host binding
 web url="auto":
 	`@url`="{{url}}"; \
+	host="127.0.0.1"; \
 	if [ "$url" = "auto" ]; then \
 		if [ -n "${WSL_DISTRO_NAME:-}" ]; then \
 			ip="$(hostname -I | awk '{print $1}')"; \
 			url="http://$ip:4443/anon"; \
+			host="0.0.0.0"; \
 		else \
 			url="http://localhost:4443/anon"; \
 		fi; \
 	fi; \
-	cd js/hang-demo && VITE_RELAY_URL="$url" bun run dev -- --host 0.0.0.0
+	cd js/hang-demo && VITE_RELAY_URL="$url" bun run dev -- --host "$host"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
web url="auto":
@url="{{url}}"; \
if [ "$url" = "auto" ]; then \
if [ -n "${WSL_DISTRO_NAME:-}" ]; then \
ip="$(hostname -I | awk '{print $1}')"; \
url="http://$ip:4443/anon"; \
else \
url="http://localhost:4443/anon"; \
fi; \
fi; \
cd js/hang-demo && VITE_RELAY_URL="$url" bun run dev -- --host 0.0.0.0
web url="auto":
`@url`="{{url}}"; \
host="127.0.0.1"; \
if [ "$url" = "auto" ]; then \
if [ -n "${WSL_DISTRO_NAME:-}" ]; then \
ip="$(hostname -I | awk '{print $1}')"; \
url="http://$ip:4443/anon"; \
host="0.0.0.0"; \
else \
url="http://localhost:4443/anon"; \
fi; \
fi; \
cd js/hang-demo && VITE_RELAY_URL="$url" bun run dev -- --host "$host"
🤖 Prompt for AI Agents
In `@justfile` around lines 269 - 279, The web recipe currently always appends
"--host 0.0.0.0" which exposes the Vite server to the LAN; change the invocation
in the web recipe (the line that runs: cd js/hang-demo && VITE_RELAY_URL="$url"
bun run dev -- --host 0.0.0.0) to only include "--host 0.0.0.0" when running
under WSL (WSL_DISTRO_NAME present) or when an explicit opt-in flag/env (e.g.,
DEV_HOST_ALL or similar) is set; otherwise omit the --host flag (or use --host
localhost) to keep the server bound to loopback. Ensure the conditional uses the
existing WSL_DISTRO_NAME check or a new opt-in env and updates the command
construction accordingly.

@kixelated
Copy link
Collaborator

@fcancela I thought you said 0.0.0.0 didn't work?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants