feat: add TLS mode toggle and update command generation for tunnel

gosunuts committed Feb 26, 2026 at 13:55 UTC 9f5041e4a41f8b5056f6b666e1ec8b5512645df7
2 files changed +41 -18
cmd/portal-tunnel/main.go
+15 -15
@@ -95,18 +95,18 @@ func runServiceTunnel(ctx context.Context, relayURLs []string) error {
95 return fmt.Errorf("no relay URLs provided")
96 }
97
98 - log.Info().Str("service", flagName).Msgf("Local service is reachable at %s", flagHost)
99 - log.Info().Str("service", flagName).Msg("Starting Portal Tunnel...")
100 - log.Info().Str("service", flagName).Msgf(" Local: %s", flagHost)
101 - log.Info().Str("service", flagName).Msgf(" Relays: %s", strings.Join(relayURLs, ", "))
102 - log.Info().Str("service", flagName).Msgf(" TLS Mode: %v", flagTLSEnable)
98 + log.Info().Msgf("Local service is reachable at %s", flagHost)
99 + log.Info().Msg("Starting Portal Tunnel...")
100 + log.Info().Msgf(" Local: %s", flagHost)
101 + log.Info().Msgf(" Relays: %s", strings.Join(relayURLs, ", "))
102 + log.Info().Msgf(" TLS Mode: %v", flagTLSEnable)
103
104 var clientOpts []sdk.ClientOption
105 clientOpts = append(clientOpts, sdk.WithBootstrapServers(relayURLs))
106
107 if flagTLSEnable {
108 clientOpts = append(clientOpts, sdk.WithTLS())
109 - log.Info().Str("service", flagName).Msg("TLS: Using relay ACME DNS-01 (E2EE)")
109 + log.Info().Msg("TLS: Using relay ACME DNS-01 (E2EE)")
110 }
111
112 client, err := sdk.NewClient(clientOpts...)
@@ -134,14 +134,14 @@ func runServiceTunnel(ctx context.Context, relayURLs []string) error {
134 _ = listener.Close()
135 }()
136
137 - log.Info().Str("service", flagName).Msg("")
138 - log.Info().Str("service", flagName).Msg("Access via:")
139 - log.Info().Str("service", flagName).Msgf("- Relay: %s", relayURLs[0])
137 + log.Info().Msg("")
138 + log.Info().Msg("Access via:")
139 + log.Info().Msgf("- Relay: %s", relayURLs[0])
140 if leaseAware, ok := listener.(interface{ LeaseID() string }); ok {
141 - log.Info().Str("service", flagName).Msgf("- Lease ID: %s", leaseAware.LeaseID())
141 + log.Info().Msgf("- Lease ID: %s", leaseAware.LeaseID())
142 }
143 if flagTLSEnable {
144 - log.Info().Str("service", flagName).Msg("- TLS: Enabled")
144 + log.Info().Msg("- TLS: Enabled")
145 }
146
147 log.Info().Str("service", flagName).Msg("")
@@ -162,13 +162,13 @@ func runServiceTunnel(ctx context.Context, relayURLs []string) error {
162 case <-ctx.Done():
163 return nil
164 default:
165 - log.Error().Str("service", flagName).Err(err).Msg("Failed to accept connection")
165 + log.Error().Err(err).Msg("Failed to accept connection")
166 continue
167 }
168 }
169
170 connCount++
171 - log.Info().Str("service", flagName).Msgf("→ [#%d] New connection from %s", connCount, relayConn.RemoteAddr())
171 + log.Info().Msgf("→ [#%d] New connection from %s", connCount, relayConn.RemoteAddr())
172
173 connWG.Add(1)
174 go func(relayConn net.Conn) {
@@ -178,9 +178,9 @@ func runServiceTunnel(ctx context.Context, relayURLs []string) error {
178 proxyType = "TLS→TCP"
179 }
180 if err := proxyConnection(ctx, flagHost, relayConn, flagTLSEnable); err != nil {
181 - log.Error().Str("service", flagName).Str("proxy", proxyType).Err(err).Msg("Proxy error")
181 + log.Error().Str("proxy", proxyType).Err(err).Msg("Proxy error")
182 }
183 - log.Info().Str("service", flagName).Str("proxy", proxyType).Msg("Connection closed")
183 + log.Info().Str("proxy", proxyType).Msg("Connection closed")
184 }(relayConn)
185 }
186 }
cmd/relay-server/frontend/src/components/TunnelCommandModal.tsx
+26 -3
@@ -34,6 +34,7 @@ export function TunnelCommandModal({ trigger }: TunnelCommandModalProps) {
34 const [urlInput, setUrlInput] = useState("");
35 const [copied, setCopied] = useState(false);
36 const [os, setOs] = useState<"unix" | "windows">("unix");
37 + const [tlsEnabled, setTlsEnabled] = useState(true);
38 const urlInputRef = useRef<HTMLInputElement>(null);
39
40 const addRelayUrl = (url: string) => {
@@ -75,11 +76,13 @@ export function TunnelCommandModal({ trigger }: TunnelCommandModalProps) {
76 relayUrls.length > 0 ? relayUrls.join(",") : currentOrigin;
77
78 if (os === "windows") {
78 - return `$ProgressPreference = 'SilentlyContinue'; $env:HOST="${hostVal}"; $env:NAME="${nameVal}"; $env:RELAY_URL="${relayUrlVal}"; irm ${currentOrigin}/tunnel?os=windows | iex`;
79 + const tlsEnv = tlsEnabled ? "" : "$env:TLS=\"false\"; ";
80 + return `$ProgressPreference = 'SilentlyContinue'; ${tlsEnv}$env:HOST="${hostVal}"; $env:NAME="${nameVal}"; $env:RELAY_URL="${relayUrlVal}"; irm ${currentOrigin}/tunnel?os=windows | iex`;
81 }
82
81 - return `curl -fsSL ${currentOrigin}/tunnel | HOST=${hostVal} NAME=${nameVal} RELAY_URL="${relayUrlVal}" sh`;
82 - }, [currentOrigin, host, name, relayUrls, os]);
83 + const tlsEnv = tlsEnabled ? "" : "TLS=false ";
84 + return `curl -fsSL ${currentOrigin}/tunnel | ${tlsEnv}HOST=${hostVal} NAME=${nameVal} RELAY_URL="${relayUrlVal}" sh`;
85 + }, [currentOrigin, host, name, relayUrls, os, tlsEnabled]);
86
87 const handleCopy = async () => {
88 try {
@@ -229,6 +232,26 @@ export function TunnelCommandModal({ trigger }: TunnelCommandModalProps) {
232 </div>
233 </div>
234
235 + {/* TLS Mode */}
236 + <div className="space-y-2">
237 + <label className="flex items-center gap-2 cursor-pointer">
238 + <input
239 + type="checkbox"
240 + checked={tlsEnabled}
241 + onChange={(e) => setTlsEnabled(e.target.checked)}
242 + className="w-4 h-4 rounded border-input cursor-pointer"
243 + />
244 + <span className="text-sm font-medium text-foreground">
245 + TLS Mode (End-to-End Encryption)
246 + </span>
247 + </label>
248 + <p className="text-xs text-text-muted">
249 + {tlsEnabled
250 + ? "End-to-end encryption with relay ACME DNS-01 certificates"
251 + : "HTTP proxy mode without TLS termination"}
252 + </p>
253 + </div>
254 +
255 {/* Generated Command */}
256 <div className="space-y-2">
257 <label className="text-sm font-medium text-foreground">