Merge pull request #30 from naturallaw777/copilot/simplify-port-forwarding-step

[WIP] Simplify port forwarding step to show required ports clearly
This commit is contained in:
Sovran_Systems
2026-04-03 15:32:59 -05:00
committed by GitHub
2 changed files with 52 additions and 88 deletions

View File

@@ -228,114 +228,79 @@ async function loadStep3() {
body.innerHTML = '<p class="onboarding-loading">Checking ports…</p>'; body.innerHTML = '<p class="onboarding-loading">Checking ports…</p>';
var networkData = null; var networkData = null;
var portHealth = null;
try { try {
var results = await Promise.all([ networkData = await apiFetch("/api/network");
apiFetch("/api/network"),
apiFetch("/api/ports/health"),
]);
networkData = results[0];
portHealth = results[1];
} catch (err) { } catch (err) {
body.innerHTML = '<p class="onboarding-error">⚠ Could not load port data: ' + escHtml(err.message) + '</p>'; body.innerHTML = '<p class="onboarding-error">⚠ Could not load network data: ' + escHtml(err.message) + '</p>';
return; return;
} }
var internalIp = (networkData && networkData.internal_ip) || "unknown"; var internalIp = (networkData && networkData.internal_ip) || "unknown";
var html = '<div class="onboarding-port-warn" style="margin-bottom:16px;">' var ip = escHtml(internalIp);
+ '⚠ <strong>IMPORTANT: Ports 80 (HTTP) and 443 (HTTPS) MUST be forwarded first.</strong><br>'
+ 'Caddy uses these ports to obtain SSL certificates from Let\'s Encrypt. ' var html = '<p class="onboarding-port-note" style="margin-bottom:14px;">'
+ 'If these ports are closed, certificate authentication will fail and ' + '⚠ <strong>Each port only needs to be forwarded once — all services share the same ports.</strong>'
+ 'none of your domain-based services will work over HTTPS.' + '</p>';
+ '</div>';
html += '<div class="onboarding-port-ip">'; html += '<div class="onboarding-port-ip">';
html += ' <span class="onboarding-port-ip-label">Forward ports to this machine\'s internal IP:</span>'; html += ' <span class="onboarding-port-ip-label">Forward ports to this machine\'s internal IP:</span>';
html += ' <span class="port-req-internal-ip">' + escHtml(internalIp) + '</span>'; html += ' <span class="port-req-internal-ip">' + ip + '</span>';
html += '</div>'; html += '</div>';
// Required ports table
html += '<div class="onboarding-port-section" style="margin-bottom:20px;">';
html += '<div class="onboarding-port-section-title" style="font-weight:700;margin-bottom:8px;">Required Ports — open these on your router:</div>';
html += '<table class="onboarding-port-table">';
html += '<thead><tr><th>Port</th><th>Protocol</th><th>Forward&nbsp;to</th><th>Purpose</th></tr></thead>';
html += '<tbody>';
html += '<tr><td class="port-req-port">80</td><td class="port-req-proto">TCP</td><td class="port-req-internal-ip">' + ip + '</td><td class="port-req-desc">HTTP</td></tr>';
html += '<tr><td class="port-req-port">443</td><td class="port-req-proto">TCP</td><td class="port-req-internal-ip">' + ip + '</td><td class="port-req-desc">HTTPS</td></tr>';
html += '<tr><td class="port-req-port">22</td><td class="port-req-proto">TCP</td><td class="port-req-internal-ip">' + ip + '</td><td class="port-req-desc">SSH Remote Access</td></tr>';
html += '<tr><td class="port-req-port">8448</td><td class="port-req-proto">TCP</td><td class="port-req-internal-ip">' + ip + '</td><td class="port-req-desc">Matrix Federation</td></tr>';
html += '</tbody></table>';
html += '</div>';
// Optional ports table
html += '<div class="onboarding-port-section" style="margin-bottom:20px;">';
html += '<div class="onboarding-port-section-title" style="font-weight:700;margin-bottom:4px;">Optional — Only needed if you enable Element Calling:</div>';
html += '<div style="font-size:0.88em;margin-bottom:8px;color:var(--color-text-muted,#888);">These 5 additional port openings are required on top of the 4 required ports above.</div>';
html += '<table class="onboarding-port-table">';
html += '<thead><tr><th>Port</th><th>Protocol</th><th>Forward&nbsp;to</th><th>Purpose</th></tr></thead>';
html += '<tbody>';
html += '<tr><td class="port-req-port">7881</td><td class="port-req-proto">TCP</td><td class="port-req-internal-ip">' + ip + '</td><td class="port-req-desc">LiveKit WebRTC signalling</td></tr>';
html += '<tr><td class="port-req-port">78827894</td><td class="port-req-proto">UDP</td><td class="port-req-internal-ip">' + ip + '</td><td class="port-req-desc">LiveKit media streams</td></tr>';
html += '<tr><td class="port-req-port">5349</td><td class="port-req-proto">TCP</td><td class="port-req-internal-ip">' + ip + '</td><td class="port-req-desc">TURN over TLS</td></tr>';
html += '<tr><td class="port-req-port">3478</td><td class="port-req-proto">UDP</td><td class="port-req-internal-ip">' + ip + '</td><td class="port-req-desc">TURN (STUN/relay)</td></tr>';
html += '<tr><td class="port-req-port">3000040000</td><td class="port-req-proto">TCP/UDP</td><td class="port-req-internal-ip">' + ip + '</td><td class="port-req-desc">TURN relay (WebRTC)</td></tr>';
html += '</tbody></table>';
html += '</div>';
// Totals
html += '<div class="onboarding-port-totals" style="margin-bottom:18px;padding:10px 14px;background:var(--color-bg-subtle,#f6f8fa);border-radius:6px;font-size:0.93em;">';
html += '<strong>Total port openings: 4</strong> (without Element Calling)<br>';
html += '<strong>Total port openings: 9</strong> (with Element Calling — 4 required + 5 optional)';
html += '</div>';
html += '<div class="onboarding-port-warn" style="margin-bottom:16px;">'
+ '⚠ <strong>Ports 80 and 443 must be forwarded first.</strong> '
+ 'Caddy uses these to obtain SSL certificates from Let\'s Encrypt. '
+ 'If they are closed, HTTPS will not work and your services will be unreachable from outside your network.'
+ '</div>';
html += '<details class="onboarding-port-details" style="margin-bottom:16px;">' html += '<details class="onboarding-port-details" style="margin-bottom:16px;">'
+ '<summary class="onboarding-port-details-summary">How to set up port forwarding</summary>' + '<summary class="onboarding-port-details-summary">How to set up port forwarding</summary>'
+ '<ol style="margin:12px 0 0 16px; padding:0; line-height:1.8;">' + '<ol style="margin:12px 0 0 16px; padding:0; line-height:1.8;">'
+ '<li>Open your router\'s admin panel — usually <code>http://192.168.1.1</code> or <code>http://192.168.0.1</code></li>' + '<li>Open your router\'s admin panel — usually <code>http://192.168.1.1</code> or <code>http://192.168.0.1</code></li>'
+ '<li>Look for <strong>"Port Forwarding"</strong>, <strong>"NAT"</strong>, or <strong>"Virtual Server"</strong> in the settings</li>' + '<li>Look for <strong>"Port Forwarding"</strong>, <strong>"NAT"</strong>, or <strong>"Virtual Server"</strong> in the settings</li>'
+ '<li>Create a new rule for each port listed below</li>' + '<li>Create a new rule for each port listed above</li>'
+ '<li>Set the destination/internal IP to <strong>' + escHtml(internalIp) + '</strong></li>' + '<li>Set the destination/internal IP to <strong>' + ip + '</strong></li>'
+ '<li>Set both internal and external port to the same number</li>' + '<li>Set both internal and external port to the same number</li>'
+ '<li>Save and apply changes</li>' + '<li>Save and apply changes</li>'
+ '</ol>' + '</ol>'
+ '</details>'; + '</details>';
var status = (portHealth && portHealth.status) || "ok";
var totalPorts = (portHealth && portHealth.total_ports) || 0;
var closedPorts = (portHealth && portHealth.closed_ports) || 0;
if (totalPorts === 0) {
html += '<p class="onboarding-body-text">No port requirements detected for your current role.</p>';
} else if (status === "ok") {
html += '<p class="onboarding-port-all-ok">✅ All ' + totalPorts + ' required ports are open and ready.</p>';
} else {
html += '<div class="onboarding-port-warn">';
html += '⚠ ' + closedPorts + ' of ' + totalPorts + ' ports appear closed. ';
html += 'You can continue, but affected services may not work until ports are forwarded.';
html += '</div>';
}
// Show per-service breakdown
var affectedSvcs = (portHealth && portHealth.affected_services) || [];
if (affectedSvcs.length > 0) {
html += '<div class="onboarding-port-breakdown">';
html += '<div class="onboarding-port-breakdown-title">Affected Services</div>';
affectedSvcs.forEach(function(svc) {
html += '<div class="onboarding-port-svc">';
html += '<div class="onboarding-port-svc-name">' + escHtml(svc.name) + '</div>';
(svc.closed_ports || []).forEach(function(p) {
html += '<div class="onboarding-port-row">';
html += ' <span class="port-status-closed">🔴</span>';
html += ' <span class="port-req-port">' + escHtml(p.port) + '/' + escHtml(p.protocol) + '</span>';
if (p.description) html += ' <span class="port-req-desc">' + escHtml(p.description) + '</span>';
html += '</div>';
});
html += '</div>';
});
html += '</div>';
}
// Full port table from services
if (_servicesData) {
// Collect all unique port requirements
var allPorts = [];
var seen = new Set();
(_servicesData || []).forEach(function(svc) {
(svc.port_requirements || []).forEach(function(p) {
var key = p.port + "/" + p.protocol;
if (!seen.has(key)) {
seen.add(key);
allPorts.push(p);
}
});
});
if (allPorts.length > 0) {
html += '<details class="onboarding-port-details">';
html += '<summary class="onboarding-port-details-summary">View All Required Ports</summary>';
html += '<table class="onboarding-port-table">';
html += '<thead><tr><th>Port</th><th>Protocol</th><th>Purpose</th></tr></thead>';
html += '<tbody>';
allPorts.forEach(function(p) {
html += '<tr>';
html += '<td class="port-req-port">' + escHtml(p.port) + '</td>';
html += '<td class="port-req-proto">' + escHtml(p.protocol) + '</td>';
html += '<td class="port-req-desc">' + escHtml(p.description || "") + '</td>';
html += '</tr>';
});
html += '</tbody></table>';
html += '</details>';
}
}
body.innerHTML = html; body.innerHTML = html;
} }

View File

@@ -93,9 +93,8 @@
<span class="onboarding-step-icon">🔌</span> <span class="onboarding-step-icon">🔌</span>
<h2 class="onboarding-step-title">Port Forwarding Check</h2> <h2 class="onboarding-step-title">Port Forwarding Check</h2>
<p class="onboarding-step-desc"> <p class="onboarding-step-desc">
Your home router must forward specific ports to this machine before your services will work. Forward these ports on your router to this machine. Each port only needs to be opened once — they are shared across all your services.
<strong>Ports 80 and 443 must be open before Caddy can authenticate your SSL certificates.</strong> <strong>Ports 80 and 443 must be open for SSL certificates to work.</strong>
Without these ports forwarded, HTTPS will not work and your services will be unreachable from outside your network.
</p> </p>
</div> </div>
<div class="onboarding-card onboarding-card--scroll" id="step-3-body"> <div class="onboarding-card onboarding-card--scroll" id="step-3-body">