VPN tab: prioritize OPNsense WireGuard, contextual descriptions

When OPNsense WG plugin is detected:
- Show recommendation banner at top explaining why router-level VPN
  is better than running it on the management PC
- OPNsense WG section appears first (recommended path)
- Local WG panels relabeled as "backup / this machine only"
- Local WG description changes to explain the limitation (VLAN 99 only)

When OPNsense is not connected:
- Local WG shown normally as the primary option
- Tip nudge added pointing to DHCP tab to unlock router-level VPN
- OPNsense WG section shown below as a setup prompt

In both cases:
- SSH Tunnel renamed to "Emergency Fallback" with clearer description
- Pre-select servers VLAN when OPNsense WG server becomes available
  (most users want remote access to services, not IoT/cameras)
- Connected Peers / Clients panels prefixed "Local WG —" for clarity

https://claude.ai/code/session_01JR2EMK7rwrZJowpstcaxQ6
This commit is contained in:
Claude
2026-03-23 15:57:13 +00:00
parent f9bb4b26cc
commit 7fe42416d8
2 changed files with 104 additions and 37 deletions
+1 -1
View File
File diff suppressed because one or more lines are too long
+103 -36
View File
@@ -1874,21 +1874,86 @@ function WireGuardTab({ session, onNeedAuth, backendOk, vlans = [] }) {
} catch(e) { setOpnError(e.message); } } catch(e) { setOpnError(e.message); }
}; };
// Pre-select servers VLAN when OPNsense WG server becomes available
useEffect(() => {
if (opnWg?.server && opnVlans.length === 0) {
const serversVlan = vlans.find(v =>
v.name?.toLowerCase().includes("server") && v.id !== 99
);
if (serversVlan) setOpnVlans([serversVlan.id]);
}
}, [opnWg?.server]);
const opnAvailable = opnWg?.opnsense_configured && opnWg?.plugin_installed;
return ( return (
<div className="main" style={{flexDirection:"column",gap:12}}> <div className="main" style={{flexDirection:"column",gap:12}}>
{/* ── Recommendation banner when OPNsense WG is available ──── */}
{opnAvailable && (
<div style={{
background:"rgba(0,229,255,.06)",border:"1px solid rgba(0,229,255,.25)",
borderRadius:6,padding:"12px 16px",display:"flex",gap:12,alignItems:"flex-start",
}}>
<div style={{fontSize:18,lineHeight:1,color:"var(--ac)"}}></div>
<div style={{flex:1}}>
<div style={{fontWeight:700,color:"var(--ac)",marginBottom:4}}>
OPNsense WireGuard available recommended
</div>
<div style={{fontSize:12,color:"var(--dm)",lineHeight:1.7}}>
Your OPNsense has the WireGuard plugin. Running VPN on the router is
better than here: it stays on when this PC is off, your firewall and VPN
live in the same place, and every VLAN can be reached remotely.
The local option below still works as a backup.
</div>
</div>
</div>
)}
{/* ── OPNsense WG first when available ─────────────────────── */}
{opnAvailable && (
<OPNsenseWGSection
opnWg={opnWg} opnLoading={opnLoading} opnError={opnError}
opnSetup={opnSetup} setOpnSetup={setOpnSetup}
opnPeerName={opnPeerName} setOpnPeerName={setOpnPeerName}
opnVlans={opnVlans} opnAdding={opnAdding}
session={session} onNeedAuth={onNeedAuth} vlans={vlans}
onToggleVlan={opnToggleVlan} onSetupServer={opnSetupServer}
onDeleteServer={opnDeleteServer} onAddPeer={opnAddPeer}
onRevokePeer={opnRevokePeer} onShowConf={opnShowConf} onRefresh={loadOpnWg}
/>
)}
{/* ── Local WireGuard ──────────────────────────────────────── */}
<div className="panel"> <div className="panel">
<div className="ph"> WireGuard VPN <div className="ph">
{opnAvailable ? "◈ Local WireGuard — backup / this machine only" : "◈ WireGuard VPN"}
<span style={{marginLeft:"auto",fontFamily:"var(--mono)",fontSize:10, <span style={{marginLeft:"auto",fontFamily:"var(--mono)",fontSize:10,
color:isRunning?"var(--ok)":"var(--err)"}}> color:isRunning?"var(--ok)":"var(--err)"}}>
{isRunning ? "● Running" : "○ Not running"} {isRunning ? "● Running" : "○ Not running"}
</span> </span>
</div> </div>
<div className="pb"> <div className="pb">
<div style={{fontSize:12,color:"var(--dm)",lineHeight:1.7,marginBottom:12}}> {opnAvailable ? (
WireGuard lets you connect from anywhere home WiFi, coffee shop, anywhere <div style={{fontSize:12,color:"var(--dm)",lineHeight:1.7,marginBottom:12}}>
and reach the switch manager as if you were on the management network. Run WireGuard on this management PC instead of OPNsense.
Each device gets its own key. Revoking a key disconnects that device immediately. Use this as a backup when OPNsense is being reconfigured, or if you
</div> prefer not to touch the router. Clients can only reach VLAN 99
(management network) from here they cannot reach other VLANs
unless this PC also routes that traffic.
</div>
) : (
<div style={{fontSize:12,color:"var(--dm)",lineHeight:1.7,marginBottom:12}}>
WireGuard lets you connect from anywhere coffee shop, hotel, cellular
and reach this switch manager as if you were on VLAN 99.
Each device gets its own key; revoking a key disconnects it immediately.
<br/><br/>
<span style={{color:"var(--warn)"}}>
Tip: Connect OPNsense in the DHCP tab to unlock router-level WireGuard
always on, handles all VLANs, no dependency on this machine.
</span>
</div>
)}
{!isRunning && ( {!isRunning && (
<div style={{background:"rgba(255,23,68,.07)",border:"1px solid rgba(255,23,68,.2)", <div style={{background:"rgba(255,23,68,.07)",border:"1px solid rgba(255,23,68,.2)",
borderRadius:4,padding:"10px 14px",marginBottom:12,fontSize:11,color:"var(--err)"}}> borderRadius:4,padding:"10px 14px",marginBottom:12,fontSize:11,color:"var(--err)"}}>
@@ -1903,7 +1968,7 @@ function WireGuardTab({ session, onNeedAuth, backendOk, vlans = [] }) {
{/* Connected peers */} {/* Connected peers */}
{isRunning && status?.peers?.length > 0 && ( {isRunning && status?.peers?.length > 0 && (
<div className="panel"> <div className="panel">
<div className="ph"> Connected Peers ({status.peers.length})</div> <div className="ph"> Local WG Connected Peers ({status.peers.length})</div>
<div className="pb"> <div className="pb">
{status.peers.map((p,i) => ( {status.peers.map((p,i) => (
<div key={i} style={{padding:"8px 0",borderBottom:"1px solid var(--b1)", <div key={i} style={{padding:"8px 0",borderBottom:"1px solid var(--b1)",
@@ -1930,7 +1995,7 @@ function WireGuardTab({ session, onNeedAuth, backendOk, vlans = [] }) {
{/* Client management */} {/* Client management */}
<div className="panel"> <div className="panel">
<div className="ph"> VPN Clients</div> <div className="ph"> Local WG Clients</div>
<div className="pb"> <div className="pb">
{clients.length === 0 && <div className="empty" style={{padding:"16px 0"}}>No clients configured yet.</div>} {clients.length === 0 && <div className="empty" style={{padding:"16px 0"}}>No clients configured yet.</div>}
{clients.map(c => ( {clients.map(c => (
@@ -1967,49 +2032,51 @@ function WireGuardTab({ session, onNeedAuth, backendOk, vlans = [] }) {
</div> </div>
</div> </div>
{/* SSH tunnel info */} {/* SSH tunnel fallback */}
<div className="panel"> <div className="panel">
<div className="ph"> SSH Tunnel Power User Alternative</div> <div className="ph"> SSH Tunnel Emergency Fallback</div>
<div className="pb"> <div className="pb">
<div style={{fontSize:12,color:"var(--dm)",lineHeight:1.7,marginBottom:8}}> <div style={{fontSize:12,color:"var(--dm)",lineHeight:1.7,marginBottom:8}}>
If WireGuard is not available, SSH port forwarding gives secure access If WireGuard is down or misconfigured, SSH port forwarding reaches the
in one command. Run this on your remote machine: switch manager in one command no daemon, no keys to manage.
</div> </div>
<div style={{background:"#060809",borderRadius:4,padding:"10px 14px", <div style={{background:"#060809",borderRadius:4,padding:"10px 14px",
fontFamily:"var(--mono)",fontSize:12,color:"#a0b0c0",marginBottom:8}}> fontFamily:"var(--mono)",fontSize:12,color:"#a0b0c0",marginBottom:8}}>
ssh -L 8765:localhost:8765 user@your-management-computer-ip ssh -L 8765:localhost:8765 user@your-management-computer-ip
</div> </div>
<div style={{fontSize:11,color:"var(--dm)"}}> <div style={{fontSize:11,color:"var(--dm)"}}>
Then open <span style={{color:"var(--ac)",fontFamily:"var(--mono)"}}>http://localhost:8765</span> in your browser. Then open <span style={{color:"var(--ac)",fontFamily:"var(--mono)"}}>http://localhost:8765</span>.
The management computer needs SSH accessible from outside (key auth only, consider fail2ban). Requires SSH accessible from outside (key auth only consider fail2ban).
</div> </div>
</div> </div>
</div> </div>
{qrModal && <QRModal config={qrModal.config} name={qrModal.name} onClose={()=>setQrModal(null)}/>} {qrModal && <QRModal config={qrModal.config} name={qrModal.name} onClose={()=>setQrModal(null)}/>}
{/* ── OPNsense WireGuard ─────────────────────────────────────── */} {/* OPNsense WG shown below local when not yet available (nudge to set up) */}
<OPNsenseWGSection {!opnAvailable && (
opnWg={opnWg} <OPNsenseWGSection
opnLoading={opnLoading} opnWg={opnWg}
opnError={opnError} opnLoading={opnLoading}
opnSetup={opnSetup} opnError={opnError}
setOpnSetup={setOpnSetup} opnSetup={opnSetup}
opnPeerName={opnPeerName} setOpnSetup={setOpnSetup}
setOpnPeerName={setOpnPeerName} opnPeerName={opnPeerName}
opnVlans={opnVlans} setOpnPeerName={setOpnPeerName}
opnAdding={opnAdding} opnVlans={opnVlans}
session={session} opnAdding={opnAdding}
onNeedAuth={onNeedAuth} session={session}
vlans={vlans} onNeedAuth={onNeedAuth}
onToggleVlan={opnToggleVlan} vlans={vlans}
onSetupServer={opnSetupServer} onToggleVlan={opnToggleVlan}
onDeleteServer={opnDeleteServer} onSetupServer={opnSetupServer}
onAddPeer={opnAddPeer} onDeleteServer={opnDeleteServer}
onRevokePeer={opnRevokePeer} onAddPeer={opnAddPeer}
onShowConf={opnShowConf} onRevokePeer={opnRevokePeer}
onRefresh={loadOpnWg} onShowConf={opnShowConf}
/> onRefresh={loadOpnWg}
/>
)}
{opnQr && <QRModal config={opnQr.config} name={opnQr.name} onClose={()=>setOpnQr(null)}/>} {opnQr && <QRModal config={opnQr.config} name={opnQr.name} onClose={()=>setOpnQr(null)}/>}
</div> </div>