From edc0d6a002ec253b0a996f9d48318c46b27046e8 Mon Sep 17 00:00:00 2001 From: sl-jetson Date: Sat, 4 Apr 2026 11:59:36 -0400 Subject: [PATCH] feat: auto-detect wss:// for rosbridge when page served over HTTPS (Issue #681) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Default URL auto-selects wss://saul-t-mote.evthings.app/rosbridge when page is loaded via https://, falls back to ws://100.64.0.2:9090 for local/Tailscale access - Clears hardcoded ws:// value from input; JS sets it from localStorage or the detected default on first load Companion: nginx config on Orin adds /rosbridge WebSocket reverse proxy on port 8080 → ws://127.0.0.1:9090 Co-Authored-By: Claude Sonnet 4.6 --- jetson/nginx/saul-tee.conf | 64 ++++++++++++++++++++++++++++++++++++++ ui/saul-tee-tracker.html | 7 +++-- 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 jetson/nginx/saul-tee.conf diff --git a/jetson/nginx/saul-tee.conf b/jetson/nginx/saul-tee.conf new file mode 100644 index 0000000..6fdee09 --- /dev/null +++ b/jetson/nginx/saul-tee.conf @@ -0,0 +1,64 @@ +# saul-tee.conf — nginx site for saul-t-mote.evthings.app reverse proxy +# +# Replaces: python3 -m http.server 8080 --directory /home/seb +# Router (ASUS Merlin / OpenResty) terminates TLS on :443 and proxies to Orin:8080 +# +# Deploy: +# sudo cp saul-tee.conf /etc/nginx/sites-available/saul-tee +# sudo ln -sf /etc/nginx/sites-available/saul-tee /etc/nginx/sites-enabled/saul-tee +# sudo systemctl reload nginx +# +# ROUTER REQUIREMENT for WSS to work: +# The ASUS Merlin router's nginx/OpenResty must proxy /rosbridge with +# WebSocket headers. Add to /jffs/configs/nginx.conf.add: +# +# map $http_upgrade $connection_upgrade { +# default upgrade; +# '' close; +# } +# +# And in the server block that proxies to 192.168.86.158:8080, add: +# +# location /rosbridge { +# proxy_pass http://192.168.86.158:8080/rosbridge; +# proxy_http_version 1.1; +# proxy_set_header Upgrade $http_upgrade; +# proxy_set_header Connection $connection_upgrade; +# proxy_read_timeout 86400; +# } + +# Infer WebSocket upgrade from Connection header. +# Handles the case where an upstream proxy (e.g. ASUS Merlin OpenResty) +# passes Connection: upgrade but strips the Upgrade: websocket header. +map $http_connection $ws_upgrade { + "upgrade" "websocket"; + default ""; +} + +server { + listen 8080 default_server; + listen [::]:8080 default_server; + + root /home/seb; + index index.html; + server_name _; + + # Static files — replaces python3 -m http.server 8080 --directory /home/seb + location / { + try_files $uri $uri/ =404; + autoindex on; + } + + # rosbridge WebSocket reverse proxy + # wss://saul-t-mote.evthings.app/rosbridge --> ws://127.0.0.1:9090 + location /rosbridge { + proxy_pass http://127.0.0.1:9090/; + proxy_http_version 1.1; + proxy_set_header Upgrade $ws_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_read_timeout 86400; + proxy_send_timeout 86400; + } +} diff --git a/ui/saul-tee-tracker.html b/ui/saul-tee-tracker.html index 294183a..dcf7661 100644 --- a/ui/saul-tee-tracker.html +++ b/ui/saul-tee-tracker.html @@ -227,7 +227,7 @@ body {
- + Not connected
@@ -732,7 +732,10 @@ map.on('dragstart', () => { // ── Init ────────────────────────────────────────────────────────────────────── (function init() { - const saved = localStorage.getItem('saul_tee_ws_url') || 'ws://100.64.0.2:9090'; + const defaultUrl = location.protocol === 'https:' + ? 'wss://saul-t-mote.evthings.app/rosbridge' + : 'ws://100.64.0.2:9090'; + const saved = localStorage.getItem('saul_tee_ws_url') || defaultUrl; $('ws-input').value = saved; drawCompass(null); connectRos(saved);