Add Streaming Hosts: native TCP/UDP port forwarding with monitoring

Also adds scripts/apply-patch.sh to automate applying patches dropped
in ~/Downloads/Claude outputs.
This commit is contained in:
marvin
2026-09-13 03:31:00 +00:00
parent d2aed579f7
commit dbc8f3490b
6 changed files with 315 additions and 35 deletions
+2
View File
@@ -144,6 +144,7 @@
<section data-admin-panel="security" class="hidden settings-panel"><h2>Security, health & updates</h2><div class="role-callout"><strong>Configuration safety</strong><span>Site Gateway validates generated Caddy configuration before every reload and retains the active configuration when validation fails.</span><strong>Container updates</strong><span>Updates are installed by pulling a new pinned image. Create a backup before changing versions.</span></div><section class="support-panel"><div><p class="eyebrow">Troubleshooting & support</p><h3>Gateway diagnostics</h3><p class="muted">Run checks and download a redacted report when you need to investigate a gateway issue.</p></div><div class="row-actions"><button id="download-support" class="button secondary admin-only">Download support report</button></div><p class="muted support-note">The report includes version, configuration health, certificate readiness, upstream checks, and recent events. Passwords, private keys, session secrets, cookies, and certificate contents are excluded.</p></section><form id="health-settings-form" class="settings-form"><label>Renewing-soon warning<input name="warningDays" type="number" min="8" max="120" value="30"><small>Days remaining before a certificate is highlighted.</small></label><label>Critical warning<input name="criticalDays" type="number" min="1" max="119" value="7"><small>Must be lower than the renewing-soon threshold.</small></label><label>Stale health data<input name="staleMinutes" type="number" min="2" max="1440" value="10"><small>Minutes before a displayed check is considered old.</small></label><div class="dialog-actions"><button class="button primary">Save health settings</button></div></form></section>
<section data-admin-panel="danger" class="hidden settings-panel danger-zone"><h2>Danger Zone</h2><p class="muted">These actions can permanently remove Site Gateway data. Review each warning carefully before continuing.</p><div class="danger-card"><p class="eyebrow">Restore defaults</p><h3>Reset gateway preferences</h3><p>Restore default site behavior, backup scheduling, certificate thresholds, and interface preferences. Your users, routes, certificates, logs, and backups remain intact.</p><button id="restore-defaults" class="button secondary">Restore default settings</button></div><div class="danger-card destructive"><p class="eyebrow">Permanent action</p><h3>Factory reset</h3><p>Deletes all Site Gateway data under <code>/data</code>, including users, routes, certificates, logs, backups, and settings. Docker-mounted files outside <code>/data</code> are not affected. The container restarts at first-install setup.</p><form id="factory-reset-form" class="danger-form"><label>Administrator username<input name="username" autocomplete="username" required></label><label>Administrator password<input name="password" type="password" autocomplete="current-password" required></label><label>Type <strong>FACTORY RESET</strong> to confirm<input name="confirmation" required autocomplete="off"></label><p id="factory-reset-error" class="error"></p><div class="danger-actions"><button class="button secondary" type="button" id="factory-reset-cancel">Cancel</button><button class="button danger" type="submit">Erase all data and reset</button></div></form></div></section>
</section>
<section id="streaming-view" class="feature-view hidden"><div id="stream-list" class="site-grid"></div><section id="stream-empty" class="empty hidden"><div class="empty-icon"></div><h2>Create your first streaming host</h2><p>Forward raw TCP or UDP traffic on a specific port straight to another host and port — no domain, no HTTPS.</p><button class="button primary create-trigger">Create a streaming host</button></section></section>
<section id="redirects-view" class="feature-view hidden"><div id="redirect-list" class="site-grid"></div><section id="redirect-empty" class="empty hidden"><div class="empty-icon"></div><h2>Create your first redirect</h2><p>Send an old domain to a new destination while preserving its path if you choose.</p><button class="button primary create-trigger">Create a redirect host</button></section></section>
<section id="access-view" class="feature-view hidden"><div id="access-list" class="data-list"></div></section>
<section id="documentation-view" class="feature-view hidden docs"><div class="docs-intro"><p class="eyebrow">Site Gateway manual</p><h2>Simple routing for homelabs and small teams</h2><p>A complete guide to publishing sites, routing applications, securing domains, and recovering safely. Start with the defaults, then use the advanced controls when you understand the trade-offs.</p><div class="docs-search-panel"><label class="doc-search"><span>Search the complete manual</span><input id="doc-search" type="search" placeholder="Search “upstream TLS”, “Plex”, “CIDR”, “backup”, or any field name"></label><small>Searches purpose, fields, examples, troubleshooting, and expert notes.</small></div></div><div class="docs-layout"><aside class="docs-nav" aria-label="Documentation sections"><p class="eyebrow">Contents</p><button data-doc-jump="introduction">Introduction</button><button data-doc-jump="dashboard">Dashboard</button><button data-doc-jump="hosted">Hosted Sites</button><button data-doc-jump="proxy">Proxy Hosts</button><button data-doc-jump="redirect">Redirect Hosts</button><button data-doc-jump="certificate">Certificates</button><button data-doc-jump="logs">Logs</button><button data-doc-jump="access">Access Lists</button><button data-doc-jump="administration">Administration</button><button data-doc-jump="backup">Backup & Restore</button><button data-doc-jump="danger">Danger Zone</button><button data-doc-jump="common">Common Controls</button></aside><div id="docs-content">
@@ -212,6 +213,7 @@
<div class="dialog-actions"><button type="button" class="button secondary close-dialog">Cancel</button><button class="button primary">Create & publish</button></div>
</form>
</dialog>
<dialog id="stream-dialog"><form id="stream-form" class="dialog-card"><div class="dialog-heading"><div><p class="eyebrow">New route</p><h2 id="stream-title">Create a streaming host</h2></div><button type="button" class="icon-button close-dialog">×</button></div><label>Name<input name="name" required placeholder="Minecraft server"></label><label>Incoming port<input name="port" type="number" min="1" max="65535" required placeholder="25565"><small>Must already be published on the container. See Documentation → Streaming hosts.</small></label><label>Forward to<input name="target" required placeholder="192.168.1.20:25565"><small>A host and port, such as 192.168.1.20:25565. No http:// — this is raw TCP/UDP, not a web address.</small></label><div class="form-grid"><label class="check-control"><input name="tcp" type="checkbox" checked><span>TCP</span></label><label class="check-control"><input name="udp" type="checkbox"><span>UDP</span></label></div><label class="check-control"><input name="healthEnabled" type="checkbox" checked><span>Monitor this target</span></label><p id="stream-error" class="error"></p><div class="dialog-actions"><button type="button" class="button secondary close-dialog">Cancel</button><button class="button primary">Create streaming host</button></div></form></dialog>
<dialog id="redirect-dialog"><form id="redirect-form" class="dialog-card"><div class="dialog-heading"><div><p class="eyebrow">New route</p><h2>Create a redirect host</h2></div><button type="button" class="icon-button close-dialog">×</button></div><label>Name<input name="name" required placeholder="Old website"></label><label>Source domain<input name="domain" required placeholder="old.example.com"></label><label>Destination<input name="target" type="url" required placeholder="https://new.example.com"></label><label>Redirect type<select name="code"><option value="302">302 · Temporary</option><option value="301">301 · Permanent</option><option value="307">307 · Temporary, preserve method</option><option value="308">308 · Permanent, preserve method</option></select></label><label>TLS<select name="tls"><option value="automatic">Automatic HTTPS</option><option value="http">HTTP only</option><option value="internal">Internal HTTPS</option></select></label><label class="check-control"><input name="preservePath" type="checkbox" checked><span>Preserve path and query</span></label><p id="redirect-error" class="error"></p><div class="dialog-actions"><button type="button" class="button secondary close-dialog">Cancel</button><button class="button primary">Create redirect</button></div></form></dialog>
<dialog id="access-dialog"><form id="access-form" class="dialog-card"><div class="dialog-heading"><div><p class="eyebrow">Reusable protection</p><h2>Create an Access List</h2></div><button type="button" class="icon-button close-dialog">×</button></div><label>Name<input name="name" required placeholder="LAN and family"></label><label>Allowed networks<textarea name="networks" placeholder="private_ranges&#10;192.168.50.0/24"></textarea><small>When supplied, every other network is denied. Use one IP, CIDR range, or private_ranges per line.</small></label><label>Denied networks <span class="optional">Optional</span><textarea name="deniedNetworks" placeholder="203.0.113.0/24"></textarea><small>These rules are evaluated before allowed networks and logins.</small></label><div id="access-credential-editor" class="credential-editor"></div><div id="access-assignment-summary" class="callout hidden"></div><p id="access-error" class="error"></p><div class="dialog-actions"><button type="button" class="button secondary close-dialog">Cancel</button><button class="button primary">Save Access List</button></div></form></dialog>