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); }
};
// 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 (
<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="ph"> WireGuard VPN
<div className="ph">
{opnAvailable ? "◈ Local WireGuard — backup / this machine only" : "◈ WireGuard VPN"}
<span style={{marginLeft:"auto",fontFamily:"var(--mono)",fontSize:10,
color:isRunning?"var(--ok)":"var(--err)"}}>
{isRunning ? "● Running" : "○ Not running"}
</span>
</div>
<div className="pb">
<div style={{fontSize:12,color:"var(--dm)",lineHeight:1.7,marginBottom:12}}>
WireGuard lets you connect from anywhere home WiFi, coffee shop, anywhere
and reach the switch manager as if you were on the management network.
Each device gets its own key. Revoking a key disconnects that device immediately.
</div>
{opnAvailable ? (
<div style={{fontSize:12,color:"var(--dm)",lineHeight:1.7,marginBottom:12}}>
Run WireGuard on this management PC instead of OPNsense.
Use this as a backup when OPNsense is being reconfigured, or if you
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 && (
<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)"}}>
@@ -1903,7 +1968,7 @@ function WireGuardTab({ session, onNeedAuth, backendOk, vlans = [] }) {
{/* Connected peers */}
{isRunning && status?.peers?.length > 0 && (
<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">
{status.peers.map((p,i) => (
<div key={i} style={{padding:"8px 0",borderBottom:"1px solid var(--b1)",
@@ -1930,7 +1995,7 @@ function WireGuardTab({ session, onNeedAuth, backendOk, vlans = [] }) {
{/* Client management */}
<div className="panel">
<div className="ph"> VPN Clients</div>
<div className="ph"> Local WG Clients</div>
<div className="pb">
{clients.length === 0 && <div className="empty" style={{padding:"16px 0"}}>No clients configured yet.</div>}
{clients.map(c => (
@@ -1967,49 +2032,51 @@ function WireGuardTab({ session, onNeedAuth, backendOk, vlans = [] }) {
</div>
</div>
{/* SSH tunnel info */}
{/* SSH tunnel fallback */}
<div className="panel">
<div className="ph"> SSH Tunnel Power User Alternative</div>
<div className="ph"> SSH Tunnel Emergency Fallback</div>
<div className="pb">
<div style={{fontSize:12,color:"var(--dm)",lineHeight:1.7,marginBottom:8}}>
If WireGuard is not available, SSH port forwarding gives secure access
in one command. Run this on your remote machine:
If WireGuard is down or misconfigured, SSH port forwarding reaches the
switch manager in one command no daemon, no keys to manage.
</div>
<div style={{background:"#060809",borderRadius:4,padding:"10px 14px",
fontFamily:"var(--mono)",fontSize:12,color:"#a0b0c0",marginBottom:8}}>
ssh -L 8765:localhost:8765 user@your-management-computer-ip
</div>
<div style={{fontSize:11,color:"var(--dm)"}}>
Then open <span style={{color:"var(--ac)",fontFamily:"var(--mono)"}}>http://localhost:8765</span> in your browser.
The management computer needs SSH accessible from outside (key auth only, consider fail2ban).
Then open <span style={{color:"var(--ac)",fontFamily:"var(--mono)"}}>http://localhost:8765</span>.
Requires SSH accessible from outside (key auth only consider fail2ban).
</div>
</div>
</div>
{qrModal && <QRModal config={qrModal.config} name={qrModal.name} onClose={()=>setQrModal(null)}/>}
{/* ── OPNsense WireGuard ─────────────────────────────────────── */}
<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}
/>
{/* OPNsense WG shown below local when not yet available (nudge to set up) */}
{!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}
/>
)}
{opnQr && <QRModal config={opnQr.config} name={opnQr.name} onClose={()=>setOpnQr(null)}/>}
</div>