feat(wg): WireGuard help topic (registration + DE/EN content + test)
parent
0342d4c6e0
commit
c9556bffbf
|
|
@ -17,7 +17,7 @@ class Index extends Component
|
||||||
/** Help topics in display order. */
|
/** Help topics in display order. */
|
||||||
private const TOPICS = [
|
private const TOPICS = [
|
||||||
'overview', 'domain-tls', 'security', 'updates', 'commands',
|
'overview', 'domain-tls', 'security', 'updates', 'commands',
|
||||||
'servers', 'sessions', 'email', 'audit', 'recovery',
|
'servers', 'sessions', 'email', 'audit', 'wireguard', 'recovery',
|
||||||
];
|
];
|
||||||
|
|
||||||
#[Url]
|
#[Url]
|
||||||
|
|
@ -51,6 +51,7 @@ class Index extends Component
|
||||||
'sessions' => __('help.topic_sessions'),
|
'sessions' => __('help.topic_sessions'),
|
||||||
'email' => __('help.topic_email'),
|
'email' => __('help.topic_email'),
|
||||||
'audit' => __('help.topic_audit'),
|
'audit' => __('help.topic_audit'),
|
||||||
|
'wireguard' => __('help.topic_wireguard'),
|
||||||
'recovery' => __('help.topic_recovery'),
|
'recovery' => __('help.topic_recovery'),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,5 +15,6 @@ return [
|
||||||
'topic_sessions' => 'Sitzungen & Benutzer',
|
'topic_sessions' => 'Sitzungen & Benutzer',
|
||||||
'topic_email' => 'E-Mail (SMTP)',
|
'topic_email' => 'E-Mail (SMTP)',
|
||||||
'topic_audit' => 'Audit-Log',
|
'topic_audit' => 'Audit-Log',
|
||||||
|
'topic_wireguard' => 'WireGuard-Zugang',
|
||||||
'topic_recovery' => 'Konto-Wiederherstellung',
|
'topic_recovery' => 'Konto-Wiederherstellung',
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -15,5 +15,6 @@ return [
|
||||||
'topic_sessions' => 'Sessions & users',
|
'topic_sessions' => 'Sessions & users',
|
||||||
'topic_email' => 'Email (SMTP)',
|
'topic_email' => 'Email (SMTP)',
|
||||||
'topic_audit' => 'Audit log',
|
'topic_audit' => 'Audit log',
|
||||||
|
'topic_wireguard' => 'WireGuard access',
|
||||||
'topic_recovery' => 'Account recovery',
|
'topic_recovery' => 'Account recovery',
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
@php
|
||||||
|
$h = 'font-display text-base font-semibold text-ink';
|
||||||
|
$p = 'text-sm leading-relaxed text-ink-2';
|
||||||
|
$li = 'text-sm leading-relaxed text-ink-2';
|
||||||
|
$code = 'rounded bg-inset px-1.5 py-0.5 font-mono text-[12px] text-accent-text';
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h3 class="{{ $h }}">Was der WireGuard-Zugang macht</h3>
|
||||||
|
<p class="{{ $p }}">Stellt das <span class="text-ink">gesamte Panel hinter einen WireGuard-Tunnel</span>: Der Server wird zum WG-Server, deine Geräte verbinden sich als Peers, und das Panel (HTTP/HTTPS, Ports 80/443) ist <span class="text-ink">nur noch über den Tunnel</span> erreichbar. Eine Netzwerk-Sperre <span class="text-ink">zusätzlich</span> zu 2FA und Anmeldeschutz: Die schützen das <span class="text-ink">Login</span>, dies verbirgt das <span class="text-ink">ganze Panel</span> vor dem öffentlichen Internet.</p>
|
||||||
|
<p class="{{ $p }}">Alles läuft über die Host-CLI <code class="{{ $code }}">clusev wg …</code> (per SSH auf dem Server). Standardmäßig ist nichts aktiv — du entscheidest, wann der Tunnel und die Sperre eingeschaltet werden.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h3 class="{{ $h }}">Einrichten — <code class="{{ $code }}">clusev wg setup</code></h3>
|
||||||
|
<p class="{{ $p }}">Interaktiv, jeder Wert mit sinnvoller Vorgabe und Erklärung:</p>
|
||||||
|
<ul class="ml-4 list-disc space-y-1.5">
|
||||||
|
<li class="{{ $li }}"><span class="text-ink">WG-Subnetz</span> (Vorgabe <code class="{{ $code }}">10.99.0.0/24</code>) — ein privates Netz, das <span class="text-ink">nicht</span> mit deinem LAN/VPN kollidieren darf. Eine Kollision wird erkannt und abgewiesen.</li>
|
||||||
|
<li class="{{ $li }}"><span class="text-ink">Öffentlicher Endpoint</span> — die automatisch erkannte öffentliche IP. <span class="text-ink">Hinter NAT oder einem Cloud-Load-Balancer ist das evtl. nicht die Adresse, die Clients wählen müssen</span> — vor dem Aktivieren der Sperre prüfen.</li>
|
||||||
|
<li class="{{ $li }}"><span class="text-ink">Erster Peer</span> — wird gleich angelegt; Konfiguration und QR-Code werden ausgegeben.</li>
|
||||||
|
</ul>
|
||||||
|
<p class="{{ $p }}">Setup startet den Tunnel (übersteht Neustarts), aktiviert aber <span class="text-ink">nicht</span> die Sperre — das Panel bleibt zunächst öffentlich.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h3 class="{{ $h }}">Client verbinden & testen</h3>
|
||||||
|
<p class="{{ $p }}">Den QR-Code aus <code class="{{ $code }}">setup</code> (oder <code class="{{ $code }}">clusev wg add-peer <name></code>) in der WireGuard-App scannen. Standard ist <span class="text-ink">Split-Tunnel</span>: nur Panel-Verkehr läuft über WG, dein normales Internet nicht. Voll-Tunnel (<code class="{{ $code }}">0.0.0.0/0</code>) ist möglich, aber <span class="text-ink">nicht empfohlen</span>.</p>
|
||||||
|
<p class="{{ $p }}">Verbinden, dann <code class="{{ $code }}">http://<Server-Tunnel-IP></code> öffnen — erreicht das Panel? Erst wenn der Tunnel sicher funktioniert, die Sperre aktivieren.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h3 class="{{ $h }}">Sperre ein/aus — <code class="{{ $code }}">clusev wg up</code> / <code class="{{ $code }}">down</code></h3>
|
||||||
|
<p class="{{ $p }}"><code class="{{ $code }}">clusev wg up</code> sperrt 80/443 auf das WG-Subnetz — von außen ist das Panel danach nicht mehr erreichbar. <code class="{{ $code }}">clusev wg status</code> zeigt Peers, Handshakes und den Sperr-Status.</p>
|
||||||
|
<p class="{{ $p }}"><span class="text-ink">Notausgang:</span> <code class="{{ $code }}">clusev wg down</code> (per SSH) entfernt die Sperre sofort — das Panel ist wieder öffentlich. <span class="text-ink">SSH (Port 22) und der WireGuard-Port sind von der Sperre nie betroffen</span>, du kommst also immer per SSH auf den Server.</p>
|
||||||
|
<p class="{{ $p }}">Schlägt <code class="{{ $code }}">wg0</code> nach einem Neustart fehl, wird die Sperre <span class="text-ink">nicht</span> angewendet — das Panel bleibt öffentlich erreichbar statt dich auszusperren.</p>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
@php
|
||||||
|
$h = 'font-display text-base font-semibold text-ink';
|
||||||
|
$p = 'text-sm leading-relaxed text-ink-2';
|
||||||
|
$li = 'text-sm leading-relaxed text-ink-2';
|
||||||
|
$code = 'rounded bg-inset px-1.5 py-0.5 font-mono text-[12px] text-accent-text';
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h3 class="{{ $h }}">What the WireGuard access does</h3>
|
||||||
|
<p class="{{ $p }}">Puts the <span class="text-ink">whole panel behind a WireGuard tunnel</span>: the server becomes a WG server, your devices peer in, and the panel (HTTP/HTTPS, ports 80/443) is reachable <span class="text-ink">only through the tunnel</span>. A network-layer gate <span class="text-ink">on top of</span> 2FA and the login protection: those guard the <span class="text-ink">login</span>; this hides the <span class="text-ink">whole panel</span> from the public internet.</p>
|
||||||
|
<p class="{{ $p }}">Everything runs through the host CLI <code class="{{ $code }}">clusev wg …</code> (over SSH on the server). Nothing is active by default — you decide when the tunnel and the gate go on.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h3 class="{{ $h }}">Set up — <code class="{{ $code }}">clusev wg setup</code></h3>
|
||||||
|
<p class="{{ $p }}">Interactive, every value pre-filled with a sensible default and a hint:</p>
|
||||||
|
<ul class="ml-4 list-disc space-y-1.5">
|
||||||
|
<li class="{{ $li }}"><span class="text-ink">WG subnet</span> (default <code class="{{ $code }}">10.99.0.0/24</code>) — a private network that must <span class="text-ink">not</span> clash with your LAN/VPN. A collision is detected and rejected.</li>
|
||||||
|
<li class="{{ $li }}"><span class="text-ink">Public endpoint</span> — the auto-detected public IP. <span class="text-ink">Behind NAT or a cloud load balancer this may not be the address clients should dial</span> — verify it before enabling the gate.</li>
|
||||||
|
<li class="{{ $li }}"><span class="text-ink">First peer</span> — created right away; its config and a QR code are printed.</li>
|
||||||
|
</ul>
|
||||||
|
<p class="{{ $p }}">Setup starts the tunnel (survives reboots) but does <span class="text-ink">not</span> enable the gate — the panel stays public for now.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h3 class="{{ $h }}">Connect a client & test</h3>
|
||||||
|
<p class="{{ $p }}">Scan the QR code from <code class="{{ $code }}">setup</code> (or <code class="{{ $code }}">clusev wg add-peer <name></code>) in the WireGuard app. The default is <span class="text-ink">split tunnel</span>: only panel traffic goes through WG, your normal internet does not. Full tunnel (<code class="{{ $code }}">0.0.0.0/0</code>) is possible but <span class="text-ink">not recommended</span>.</p>
|
||||||
|
<p class="{{ $p }}">Connect, then open <code class="{{ $code }}">http://<server-tunnel-ip></code> — does it reach the panel? Only once the tunnel reliably works, enable the gate.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<h3 class="{{ $h }}">Gate on/off — <code class="{{ $code }}">clusev wg up</code> / <code class="{{ $code }}">down</code></h3>
|
||||||
|
<p class="{{ $p }}"><code class="{{ $code }}">clusev wg up</code> restricts 80/443 to the WG subnet — from outside the panel is then unreachable. <code class="{{ $code }}">clusev wg status</code> shows peers, handshakes and the gate state.</p>
|
||||||
|
<p class="{{ $p }}"><span class="text-ink">Escape hatch:</span> <code class="{{ $code }}">clusev wg down</code> (over SSH) removes the gate immediately — the panel is public again. <span class="text-ink">SSH (port 22) and the WireGuard port are never affected by the gate</span>, so you can always reach the server over SSH.</p>
|
||||||
|
<p class="{{ $p }}">If <code class="{{ $code }}">wg0</code> fails to come up after a reboot, the gate is <span class="text-ink">not</span> applied — the panel stays publicly reachable rather than locking you out.</p>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Livewire\Help\Index;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Livewire\Livewire;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class HelpWireguardTopicTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->actingAs(User::factory()->create(['must_change_password' => false]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_wireguard_is_a_known_topic_and_renders(): void
|
||||||
|
{
|
||||||
|
Livewire::test(Index::class, ['topic' => 'wireguard'])
|
||||||
|
->assertSet('topic', 'wireguard')
|
||||||
|
->assertSee('WireGuard');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_wireguard_label_exists_in_both_locales(): void
|
||||||
|
{
|
||||||
|
$this->assertSame('WireGuard-Zugang', __('help.topic_wireguard', [], 'de'));
|
||||||
|
$this->assertSame('WireGuard access', __('help.topic_wireguard', [], 'en'));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue