Set the internal and external port to the same number. You only need to do this once — all your services share these two ports. Test from your phone on mobile data (your home network may not support hairpin NAT / loopback).
' +
- '
';
+ /* Router ports — repo wording (domain-prereqs.js / server.py).
+ Node-only role: ports matter only once BTCPay Server or Lightning
+ Wallet Connections (LNURL) is turned on — until then, no router task. */
+ if (isNodeRole() && !hasEnabledDomainService(services)) {
+ html += '
' +
+ '
' + icon("g-wifi") + 'Router
' +
+ '
' + icon("g-check") + 'No router setup needed yet
' +
+ '
Ports 80 and 443 only need to be forwarded on your router if you turn on BTCPay Server or Lightning Wallet Connections (LNURL). If you enable one of them, come back here — this card will show exactly what to do.
Set the internal and external port to the same number. You only need to do this once — all your services share these two ports.
' +
+ '
';
+ }
/* Live domain diagnostics (sequential checklist from the backend —
same data the domain-service modals show) */
@@ -269,10 +289,13 @@
'
Checking…
' +
'';
- /* Who uses these ports */
- html += '
' +
- '
' + icon("g-antenna") + 'Who uses these ports
' +
- '
' + whoUsesPorts() + '
';
+ /* Who uses these ports (redundant on a Node install with no domain
+ services on — the router note above already covers it) */
+ if (!isNodeRole() || hasEnabledDomainService(services)) {
+ html += '
' +
+ '
' + icon("g-antenna") + 'Who uses these ports
' +
+ '
' + whoUsesPorts() + '
';
+ }
$sysBody.innerHTML = html;
$sysModal.classList.add("open");
@@ -281,7 +304,7 @@
var checkCard = document.getElementById("sys-check-card");
var stepsEl = document.getElementById("sys-check-steps");
var units = DOMAIN_UNITS.filter(function (u) {
- return services.some(function (s) { return s.unit === u; });
+ return services.some(function (s) { return s.unit === u && s.enabled; });
});
if (!units.length || !checkCard || !stepsEl) return;
checkCard.style.display = "";
diff --git a/app/sovran_systemsos_web/static/js/features.js b/app/sovran_systemsos_web/static/js/features.js
index 8287ff6..99f2b0b 100644
--- a/app/sovran_systemsos_web/static/js/features.js
+++ b/app/sovran_systemsos_web/static/js/features.js
@@ -97,7 +97,6 @@ function openDomainSetupModal(feat, onSaved) {
nwcWarning +
renderDomainNeedsHtml({ serviceName: feat.name, hostExample: hostExample, purpose: purpose }) +
renderNjallaStepsHtml({ hostExample: hostExample, pasteHint: "below" }) +
- '' +
'
Enter the address for this service and paste the update command from Njal.la.
' +
'' +
'' +
@@ -144,8 +143,6 @@ function openDomainSetupModal(feat, onSaved) {
$domainSetupModal.classList.add("open");
- // Fill the router port-forwarding box with this computer's LAN IP (best-effort)
- renderRouterPortsBox("domain-router-box");
}
function openDomainReconfigureModal(feat, existingDomain, onSaved) {
@@ -193,9 +190,7 @@ function openDomainReconfigureModal(feat, existingDomain, onSaved) {
'' + escHtml(externalIp) + '' +
'
If the IP is wrong or the record is missing, update it
' +
'
If you changed the DDNS curl command, paste the updated one below
' +
- '
Confirm ports 80 and 443 (TCP) are still forwarded on your router to this computer — see the reminder below:
' +
'' +
- '' +
'' +
'' +
'
ℹ Paste the full curl command from your Njal.la dashboard\'s Dynamic record
' +
@@ -241,8 +236,6 @@ function openDomainReconfigureModal(feat, existingDomain, onSaved) {
$domainSetupModal.classList.add("open");
- // Fill the router port-forwarding box with this computer's LAN IP (best-effort)
- renderRouterPortsBox("domain-router-box");
}
function closeDomainSetupModal() {
diff --git a/app/sovran_systemsos_web/static/js/service-detail.js b/app/sovran_systemsos_web/static/js/service-detail.js
index 0d6e095..41e4551 100644
--- a/app/sovran_systemsos_web/static/js/service-detail.js
+++ b/app/sovran_systemsos_web/static/js/service-detail.js
@@ -718,7 +718,11 @@ async function openServiceDetailModal(unit, name, icon) {
// Section C: Domain diagnostics (domain services)
if (data.needs_domain) {
- var steps = data.domain_check_steps || [];
+ // The Hub shows only the domain-active step here; the full DNS and
+ // port diagnostics live in the Systems Operational modal.
+ var steps = (data.domain_check_steps || []).filter(function (s) {
+ return Number(s.step) === 1;
+ });
var stepsHtml = "";
steps.forEach(function(step) {
var iconLabel = "—";
@@ -747,6 +751,17 @@ async function openServiceDetailModal(unit, name, icon) {
domainActionHtml +
'');
+ // Node-only role: BTCPay Server and Lightning Wallet Connections are
+ // the domain services — surface the router task here. (Desktop + Server
+ // set this up during onboarding; Systems Operational shows it too.)
+ if (typeof _currentRole !== "undefined" && _currentRole === "node" &&
+ (unit === "btcpayserver.service" || unit === "albyhub.service")) {
+ addSetup('
' +
+ '
Ports to Forward in Your Router
' +
+ '' +
+ '
');
+ }
+
if (data.router_ports && data.router_ports.length > 0) {
var trimmedInternalIp = data.internal_ip ? String(data.internal_ip).trim() : "";
addSetup('
' +
@@ -1004,6 +1019,9 @@ async function openServiceDetailModal(unit, name, icon) {
$credsBody.innerHTML = html;
if (isNwc) _nwcWireTabs();
_attachCopyHandlers($credsBody);
+ if (document.getElementById("svc-node-router-box")) {
+ renderRouterPortsBox("svc-node-router-box");
+ }
if (_isNwcServiceUnit(unit) && (effectiveEnabled || data.enabled)) {
await _nwcInitWalletFlow(unit, name, icon);
var nwcRtlBtn = document.getElementById("nwc-open-rtl-btn");
diff --git a/app/sovran_systemsos_web/templates/index.html b/app/sovran_systemsos_web/templates/index.html
index dc4073a..3f9f57a 100644
--- a/app/sovran_systemsos_web/templates/index.html
+++ b/app/sovran_systemsos_web/templates/index.html
@@ -18,26 +18,7 @@
-