ux: simplify domain and router setup guidance
This commit is contained in:
@@ -246,8 +246,8 @@ CATEGORY_ORDER = [
|
|||||||
FEATURE_REGISTRY = [
|
FEATURE_REGISTRY = [
|
||||||
{
|
{
|
||||||
"id": "rdp",
|
"id": "rdp",
|
||||||
"name": "Remote Desktop (RDP)",
|
"name": "Remote Desktop",
|
||||||
"description": "Access your desktop remotely via RDP client",
|
"description": "Access your desktop from a device on your home network — no router setup needed",
|
||||||
"category": "infrastructure",
|
"category": "infrastructure",
|
||||||
"needs_domain": False,
|
"needs_domain": False,
|
||||||
"domain_name": None,
|
"domain_name": None,
|
||||||
@@ -362,8 +362,8 @@ FEATURE_REGISTRY = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "btcpay-web",
|
"id": "btcpay-web",
|
||||||
"name": "BTCPay Server Web Access",
|
"name": "Put BTCPay Server Online",
|
||||||
"description": "Expose BTCPay Server to the internet via your domain. When disabled, BTCPay Server still runs locally but is not accessible from the web.",
|
"description": "Let people donate Bitcoin, pay you, or visit your online store. BTCPay Server stays private when this is turned off.",
|
||||||
"category": "bitcoin",
|
"category": "bitcoin",
|
||||||
"needs_domain": True,
|
"needs_domain": True,
|
||||||
"domain_name": "btcpayserver",
|
"domain_name": "btcpayserver",
|
||||||
@@ -545,9 +545,9 @@ SERVICE_DESCRIPTIONS: dict[str, str] = {
|
|||||||
"Addresses on your Sovran_SystemsOS node."
|
"Addresses on your Sovran_SystemsOS node."
|
||||||
),
|
),
|
||||||
"gnome-remote-desktop.service": (
|
"gnome-remote-desktop.service": (
|
||||||
"Access your server's full desktop environment from anywhere using any RDP client. "
|
"Access your desktop from a device on your home network — no router setup needed. "
|
||||||
"Manage your system visually without being physically present. "
|
"Sovran_SystemsOS creates the address, username, and password for you: "
|
||||||
"Sovran_SystemsOS sets up secure remote access with generated credentials — connect and go."
|
"just open an RDP app and connect."
|
||||||
),
|
),
|
||||||
"sshd.service": (
|
"sshd.service": (
|
||||||
"Secure Shell (SSH) remote access. When enabled, authorized users can connect "
|
"Secure Shell (SSH) remote access. When enabled, authorized users can connect "
|
||||||
|
|||||||
@@ -1,22 +1,14 @@
|
|||||||
/* Sovran_SystemsOS Hub — Shared domain-prerequisite instructions.
|
/* Sovran_SystemsOS Hub — Shared domain and router instructions.
|
||||||
|
|
||||||
SINGLE SOURCE OF TRUTH for the "you need a Njal.la domain + router port
|
This is the single source of truth for the simple setup guidance shown in:
|
||||||
forwarding" guidance that must read identically everywhere it appears:
|
|
||||||
|
|
||||||
• First-boot onboarding wizard (Server + Desktop role)
|
• First-boot onboarding for Server + Desktop
|
||||||
— onboarding.js step 3
|
• Feature setup in the Hub
|
||||||
• Feature-enable domain modal (Node role, and any role)
|
• Domain reconfiguration and troubleshooting
|
||||||
— features.js openDomainSetupModal()
|
|
||||||
(Lightning Wallet Connections / NWC, BTCPay Server, Haven, …)
|
|
||||||
• Domain reconfigure / troubleshooting modal
|
|
||||||
— features.js openDomainReconfigureModal()
|
|
||||||
|
|
||||||
Keep these three surfaces word-for-word consistent: always edit this
|
Keep the wording consistent by editing it here. */
|
||||||
file, never fork the wording inline. Plain classic script (no modules) —
|
|
||||||
both templates load it with a plain <script> tag. */
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/* Escape helper local to this file so it is self-contained on both pages. */
|
|
||||||
function dpEsc(str) {
|
function dpEsc(str) {
|
||||||
return String(str)
|
return String(str)
|
||||||
.replace(/&/g, "&")
|
.replace(/&/g, "&")
|
||||||
@@ -26,105 +18,71 @@ function dpEsc(str) {
|
|||||||
.replace(/'/g, "'");
|
.replace(/'/g, "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── "What you'll need" intro ──────────────────────────────────────
|
/* Explain only what the user needs for the step in front of them. */
|
||||||
opts.serviceName — e.g. "Lightning Wallet Connections", or null for
|
|
||||||
the multi-service (onboarding) wording.
|
|
||||||
opts.hostExample — e.g. "lightning" → lightning.yourdomain.com */
|
|
||||||
function renderDomainNeedsHtml(opts) {
|
function renderDomainNeedsHtml(opts) {
|
||||||
|
opts = opts || {};
|
||||||
var serviceName = opts.serviceName || null;
|
var serviceName = opts.serviceName || null;
|
||||||
var hostExample = dpEsc(opts.hostExample || "myservice");
|
var purpose = opts.purpose || "";
|
||||||
var html = "";
|
var html = "";
|
||||||
|
|
||||||
if (serviceName) {
|
if (purpose === "btcpay") {
|
||||||
html += "<p>To enable <strong>" + dpEsc(serviceName) + "</strong>, you'll need two things first:</p>";
|
html += "<p><strong>Put your BTCPay Server online</strong></p>";
|
||||||
html += '<ol style="margin:8px 0 0 16px;padding:0;line-height:1.7;">';
|
html += "<p>Let people donate Bitcoin, pay you, or visit your online store.</p>";
|
||||||
html += "<li><strong>A domain of your own from <a href=\"https://njal.la\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"color:var(--accent-color);\">Njal.la</a></strong> "
|
html += "<p>BTCPay Server needs a domain so people can reach it. "
|
||||||
+ "— privacy-friendly, no personal details required, accepts Bitcoin. "
|
+ "Sovran_SystemsOS walks you through getting your domain from "
|
||||||
+ dpEsc(serviceName) + " gets its own hostname: a subdomain (e.g. <code>" + hostExample + ".yourdomain.com</code>) "
|
+ '<a href="https://njal.la" target="_blank" rel="noopener noreferrer" style="color:var(--accent-color);">Njal.la</a>'
|
||||||
+ "or a separate domain — your choice. Subdomains are free, and one domain can have many.</li>";
|
+ " and connecting it. Just follow the steps below.</p>";
|
||||||
html += "<li><strong>Access to your router</strong> — you'll forward ports <strong>80</strong> and <strong>443</strong> (TCP) "
|
} else if (serviceName) {
|
||||||
+ "to this computer once. All domain-based services share these two ports; "
|
html += "<p>To make <strong>" + dpEsc(serviceName) + "</strong> available outside your home, it needs a domain.</p>";
|
||||||
+ "they're required for HTTPS and SSL certificates.</li>";
|
html += "<p>Sovran_SystemsOS walks you through getting your domain from "
|
||||||
html += "</ol>";
|
+ '<a href="https://njal.la" target="_blank" rel="noopener noreferrer" style="color:var(--accent-color);">Njal.la</a>'
|
||||||
|
+ " and connecting it. Just follow the steps below.</p>";
|
||||||
} else {
|
} else {
|
||||||
html += "<p><strong>Each service below needs two things set up:</strong></p>";
|
html += "<p>Your domain is the address people use to reach your services on the internet.</p>";
|
||||||
html += '<ol style="margin:8px 0 0 16px;padding:0;line-height:1.7;">';
|
html += "<p>Sovran_SystemsOS walks you through getting your domain from "
|
||||||
html += "<li><strong>A domain of your own from <a href=\"https://njal.la\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"color:var(--accent-color);\">Njal.la</a></strong> "
|
+ '<a href="https://njal.la" target="_blank" rel="noopener noreferrer" style="color:var(--accent-color);">Njal.la</a>'
|
||||||
+ "— privacy-friendly, no personal details required, accepts Bitcoin. "
|
+ " and connecting your services. Just follow the steps below.</p>";
|
||||||
+ "Each service gets its own hostname: its own subdomain (e.g. <code>" + hostExample + ".yourdomain.com</code>) "
|
|
||||||
+ "or a separate domain — your choice. Subdomains are free, and one domain can have many, "
|
|
||||||
+ "so a single domain can serve every service.</li>";
|
|
||||||
html += "<li><strong>Access to your router</strong> — you'll forward ports <strong>80</strong> and <strong>443</strong> (TCP) "
|
|
||||||
+ "to this computer once. All domain-based services share these two ports; "
|
|
||||||
+ "they're required for HTTPS and SSL certificates.</li>";
|
|
||||||
html += "</ol>";
|
|
||||||
}
|
}
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── "How to set it up at Njal.la" steps ───────────────────────────
|
/* The shortest Njal.la steps that still tell the user exactly what to do. */
|
||||||
opts.hostExample — host part used in the examples (default "call").
|
|
||||||
opts.pasteHint — where the curl command goes:
|
|
||||||
"below" (single service) or "next to its service below"
|
|
||||||
(onboarding, many services). */
|
|
||||||
function renderNjallaStepsHtml(opts) {
|
function renderNjallaStepsHtml(opts) {
|
||||||
var hostExample = dpEsc((opts && opts.hostExample) || "call");
|
var hostExample = dpEsc((opts && opts.hostExample) || "call");
|
||||||
var pasteHint = (opts && opts.pasteHint) || "below";
|
var pasteHint = (opts && opts.pasteHint) || "below";
|
||||||
var html = "";
|
var html = "";
|
||||||
|
|
||||||
html += "<p style=\"margin-top:12px;\"><strong>How to set it up at Njal.la:</strong></p>";
|
html += '<p style="margin-top:12px;"><strong>Get and connect your domain:</strong></p>';
|
||||||
html += '<ol style="margin:8px 0 0 16px;padding:0;line-height:1.7;">';
|
html += '<ol style="margin:8px 0 0 16px;padding:0;line-height:1.7;">';
|
||||||
html += "<li>Create an account at <a href=\"https://njal.la\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"color:var(--accent-color);\">https://njal.la</a> and buy a domain.</li>";
|
html += '<li>Open <a href="https://njal.la" target="_blank" rel="noopener noreferrer" style="color:var(--accent-color);">Njal.la</a>, create an account, and get a domain.</li>';
|
||||||
html += "<li>Add a <strong>Dynamic</strong> record for the hostname:"
|
html += "<li>Open your domain and add a <strong>Dynamic</strong> record for this service. "
|
||||||
+ '<ul style="margin:4px 0 0 16px;padding:0;line-height:1.7;">'
|
+ "In the <strong>Name</strong> box, enter only the first part of the address. "
|
||||||
+ "<li>In the Njal.la <strong>Name</strong> field, type ONLY the host part — the word before your domain.<br>"
|
+ "For <code>" + hostExample + ".yourdomain.com</code>, enter <code>" + hostExample + "</code>. "
|
||||||
+ "(For "" + hostExample + ".yourdomain.com" you'd type just: <code>" + hostExample + "</code>.)<br>"
|
+ "If you are using the whole domain, leave the box blank or enter <code>@</code>.</li>";
|
||||||
+ "⚠ Do NOT type the full domain here — Njal.la adds it automatically.</li>"
|
html += "<li>Copy the update command Njal.la gives you and paste it " + pasteHint + ".</li>";
|
||||||
+ "<li>Dedicating a whole separate domain to this service? Leave the Name field blank or use <code>@</code>.</li>"
|
|
||||||
+ "</ul>"
|
|
||||||
+ "</li>";
|
|
||||||
html += "<li>A Dynamic record has <strong>NO IP field</strong> — you don't enter an IP anywhere. "
|
|
||||||
+ "It auto-fills once Sovran_SystemsOS runs the update command (on save, and again after every reboot).</li>";
|
|
||||||
html += "<li>Njal.la gives you a curl command, e.g.:<br>"
|
|
||||||
+ '<code style="font-size:0.8em;">curl "https://njal.la/update/?h=' + hostExample + '.yourdomain.com&k=abc123&auto"</code><br>'
|
|
||||||
+ "Copy it and paste it " + pasteHint + ".</li>";
|
|
||||||
html += "</ol>";
|
html += "</ol>";
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── "One router task" port-forwarding box ─────────────────────────
|
/* One router task shared by all normal domain-based services. */
|
||||||
opts.internalIp — LAN IP string, or empty/null for generic wording.
|
|
||||||
opts.plural — true for multi-service (onboarding) wording.
|
|
||||||
opts.includeSsh — also mention port 22 for SSH (onboarding).
|
|
||||||
opts.extraNote — extra sentence appended at the end (optional). */
|
|
||||||
function renderRouterPortsHtml(opts) {
|
function renderRouterPortsHtml(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
var ipPart = opts.internalIp
|
var ipPart = opts.internalIp
|
||||||
? " to this computer’s internal IP <strong>" + dpEsc(opts.internalIp) + "</strong>"
|
? " to this computer at <strong>" + dpEsc(opts.internalIp) + "</strong>"
|
||||||
: " to this computer’s internal IP";
|
: " to this computer";
|
||||||
var serviceWord = opts.plural ? "services" : "service";
|
|
||||||
|
|
||||||
var html = "";
|
var html = "";
|
||||||
html += "🔌 <strong>One router task:</strong> in your router’s <strong>port forwarding</strong> settings, "
|
html += "🔌 <strong>One router task:</strong> in your router’s <strong>Port Forwarding</strong> settings, "
|
||||||
+ "forward port <strong>80 (TCP)</strong> and port <strong>443 (TCP)</strong>"
|
+ "forward <strong>80 (TCP)</strong> and <strong>443 (TCP)</strong>"
|
||||||
+ ipPart + ". Use the <strong>same number for the internal and external port</strong>. "
|
+ ipPart + ". If your router asks for outside and inside port numbers, use the same number for both. "
|
||||||
+ "This only needs to be done once — all domain services share these ports — "
|
+ "You only need to do this once. All your services share these two ports.";
|
||||||
+ "but HTTPS and SSL certificates won’t work without them, so your " + serviceWord + " "
|
|
||||||
+ "can’t be reached from outside your home network. "
|
|
||||||
+ "You’ll need normal access to your router’s settings with working port forwarding — "
|
|
||||||
+ "if your ISP blocks it (e.g. CGNAT), domain-based services can’t be reached from the internet. ";
|
|
||||||
if (opts.includeSsh) {
|
|
||||||
html += "Add port <strong>22 (TCP)</strong> as well if you want remote SSH access. ";
|
|
||||||
}
|
|
||||||
if (opts.extraNote) {
|
if (opts.extraNote) {
|
||||||
html += dpEsc(opts.extraNote);
|
html += " " + dpEsc(opts.extraNote);
|
||||||
}
|
}
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Async helper: fill a router-box container with the internal IP ──
|
/* Show generic wording immediately, then add the computer's address when found. */
|
||||||
Renders generic text immediately, then upgrades to the concrete LAN IP
|
|
||||||
if /api/network provides one. Best-effort — never blocks the UI. */
|
|
||||||
function renderRouterPortsBox(elId, opts) {
|
function renderRouterPortsBox(elId, opts) {
|
||||||
var el = document.getElementById(elId);
|
var el = document.getElementById(elId);
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
@@ -142,5 +100,5 @@ function renderRouterPortsBox(elId, opts) {
|
|||||||
target.innerHTML = renderRouterPortsHtml(next);
|
target.innerHTML = renderRouterPortsHtml(next);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(function() { /* generic wording already shown — fine */ });
|
.catch(function() { /* Generic wording is already shown. */ });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ function openDomainSetupModal(feat, onSaved) {
|
|||||||
if ($domainSetupTitle) $domainSetupTitle.textContent = "🌐 Domain Setup — " + feat.name;
|
if ($domainSetupTitle) $domainSetupTitle.textContent = "🌐 Domain Setup — " + feat.name;
|
||||||
|
|
||||||
var isWalletConnections = (feat.id === "nwc-wallets" || feat.domain_name === "lightning");
|
var isWalletConnections = (feat.id === "nwc-wallets" || feat.domain_name === "lightning");
|
||||||
|
var isBtcpay = feat.id === "btcpay-web";
|
||||||
|
|
||||||
var npubField = "";
|
var npubField = "";
|
||||||
if (feat.id === "haven") {
|
if (feat.id === "haven") {
|
||||||
@@ -77,30 +78,30 @@ function openDomainSetupModal(feat, onSaved) {
|
|||||||
|
|
||||||
var nwcWarning = isWalletConnections
|
var nwcWarning = isWalletConnections
|
||||||
? '<div class="domain-nwc-warning">' +
|
? '<div class="domain-nwc-warning">' +
|
||||||
'<strong>⚠ Lightning Wallet Connections requires its own unique hostname.</strong> ' +
|
'<strong>Lightning Wallet Connections needs its own address.</strong> ' +
|
||||||
'Use a new subdomain such as <code>lightning.yourdomain.com</code>, or a separate domain. ' +
|
'Use a new address such as <code>lightning.yourdomain.com</code>. Do not use an address already connected to another service.' +
|
||||||
'Do not reuse a domain already assigned to Matrix, Nextcloud, WordPress, BTCPay Server, Vaultwarden, Haven, or another Caddy site.' +
|
|
||||||
'</div>'
|
'</div>'
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
var domainPlaceholder = isWalletConnections ? "lightning.yourdomain.com" : "myservice.example.com";
|
var domainPlaceholder = isWalletConnections ? "lightning.yourdomain.com" : (isBtcpay ? "btcpay.yourdomain.com" : "myservice.example.com");
|
||||||
var domainLabelExample = isWalletConnections ? "lightning.yourdomain.com" : "call.yourdomain.com";
|
var domainLabelExample = isWalletConnections ? "lightning.yourdomain.com" : (isBtcpay ? "btcpay.yourdomain.com" : "call.yourdomain.com");
|
||||||
|
|
||||||
// Shared instructions (single source of truth: static/js/domain-prereqs.js) —
|
// Shared instructions (single source of truth: static/js/domain-prereqs.js) —
|
||||||
// identical wording to the Server + Desktop onboarding wizard and every other
|
// identical wording to the Server + Desktop onboarding wizard and every other
|
||||||
// domain-based feature, regardless of role (Node / Desktop / Server+Desktop).
|
// domain-based feature, regardless of role (Node / Desktop / Server+Desktop).
|
||||||
var hostExample = isWalletConnections ? "lightning" : "call";
|
var hostExample = isWalletConnections ? "lightning" : (isBtcpay ? "btcpay" : "call");
|
||||||
|
var purpose = isBtcpay ? "btcpay" : "";
|
||||||
|
|
||||||
$domainSetupBody.innerHTML =
|
$domainSetupBody.innerHTML =
|
||||||
'<div class="domain-setup-intro">' +
|
'<div class="domain-setup-intro">' +
|
||||||
nwcWarning +
|
nwcWarning +
|
||||||
renderDomainNeedsHtml({ serviceName: feat.name, hostExample: hostExample }) +
|
renderDomainNeedsHtml({ serviceName: feat.name, hostExample: hostExample, purpose: purpose }) +
|
||||||
renderNjallaStepsHtml({ hostExample: hostExample, pasteHint: "below" }) +
|
renderNjallaStepsHtml({ hostExample: hostExample, pasteHint: "below" }) +
|
||||||
'<div class="onboarding-port-warn" id="domain-router-box" style="margin-top:12px;"></div>' +
|
'<div class="onboarding-port-warn" id="domain-router-box" style="margin-top:12px;"></div>' +
|
||||||
'<p style="margin-top:10px;">Below, enter the full domain for this service — a subdomain (e.g. ' + domainLabelExample + ') or a separate domain — and paste its curl command.</p>' +
|
'<p style="margin-top:10px;">Enter the address for this service and paste the update command from Njal.la.</p>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<div class="domain-field-group"><label class="domain-field-label" for="domain-subdomain-input">Service domain (e.g. ' + domainLabelExample + '):</label><input class="domain-field-input" type="text" id="domain-subdomain-input" placeholder="' + domainPlaceholder + '" /></div>' +
|
'<div class="domain-field-group"><label class="domain-field-label" for="domain-subdomain-input">Service address (e.g. ' + domainLabelExample + '):</label><input class="domain-field-input" type="text" id="domain-subdomain-input" placeholder="' + domainPlaceholder + '" /></div>' +
|
||||||
'<div class="domain-field-group"><label class="domain-field-label" for="domain-ddns-input">Njal.la Dynamic DNS Update Command:</label><input class="domain-field-input" type="text" id="domain-ddns-input" placeholder="curl "https://njal.la/update/?h=' + domainPlaceholder + '&k=abc123&auto"" /><p class="domain-field-hint">ℹ Paste the full curl command from your Njal.la dashboard\'s Dynamic record</p></div>' +
|
'<div class="domain-field-group"><label class="domain-field-label" for="domain-ddns-input">Njal.la Update Command:</label><input class="domain-field-input" type="text" id="domain-ddns-input" placeholder="curl "https://njal.la/update/?h=' + domainPlaceholder + '&k=abc123&auto"" /><p class="domain-field-hint">Paste the update command from Njal.la</p></div>' +
|
||||||
npubField +
|
npubField +
|
||||||
'<div class="domain-field-actions"><button class="btn btn-close-modal" id="domain-setup-cancel-btn">Cancel</button><button class="btn btn-primary" id="domain-setup-save-btn">Save & Enable</button></div>';
|
'<div class="domain-field-actions"><button class="btn btn-close-modal" id="domain-setup-cancel-btn">Cancel</button><button class="btn btn-primary" id="domain-setup-save-btn">Save & Enable</button></div>';
|
||||||
|
|
||||||
@@ -169,9 +170,8 @@ function openDomainReconfigureModal(feat, existingDomain, onSaved) {
|
|||||||
|
|
||||||
var nwcWarning = isWalletConnections
|
var nwcWarning = isWalletConnections
|
||||||
? '<div class="domain-nwc-warning">' +
|
? '<div class="domain-nwc-warning">' +
|
||||||
'<strong>⚠ Lightning Wallet Connections requires its own unique hostname.</strong> ' +
|
'<strong>Lightning Wallet Connections needs its own address.</strong> ' +
|
||||||
'Use a new subdomain such as <code>lightning.yourdomain.com</code>, or a separate domain. ' +
|
'Use a new address such as <code>lightning.yourdomain.com</code>. Do not use an address already connected to another service.' +
|
||||||
'Do not reuse a domain already assigned to Matrix, Nextcloud, WordPress, BTCPay Server, Vaultwarden, Haven, or another Caddy site.' +
|
|
||||||
'</div>'
|
'</div>'
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
|
|||||||
@@ -364,17 +364,12 @@ async function loadStep3() {
|
|||||||
+ renderDomainNeedsHtml({ serviceName: null, hostExample: "call" })
|
+ renderDomainNeedsHtml({ serviceName: null, hostExample: "call" })
|
||||||
+ renderNjallaStepsHtml({ hostExample: "call", pasteHint: "next to its service below" })
|
+ renderNjallaStepsHtml({ hostExample: "call", pasteHint: "next to its service below" })
|
||||||
+ '</div>';
|
+ '</div>';
|
||||||
html += '<p class="onboarding-hint">Enter each service\'s full domain — a subdomain (e.g. <code>call.yourdomain.com</code>) or a separate domain (e.g. <code>call.com</code>) — and its Njal.la DDNS curl command.</p>';
|
html += '<p class="onboarding-hint">Enter the address for each service and paste its update command from Njal.la.</p>';
|
||||||
|
|
||||||
// Router note (the same wording is shown again, per-service, whenever a
|
// Router note (the same wording is shown again, per-service, whenever a
|
||||||
// domain-based feature is enabled, and lives on each service tile afterwards)
|
// domain-based feature is enabled, and lives on each service tile afterwards)
|
||||||
html += '<div class="onboarding-port-warn" style="margin-bottom:16px;">'
|
html += '<div class="onboarding-port-warn" style="margin-bottom:16px;">'
|
||||||
+ renderRouterPortsHtml({
|
+ renderRouterPortsHtml({ internalIp: internalIp })
|
||||||
internalIp: internalIp,
|
|
||||||
plural: true,
|
|
||||||
includeSsh: true,
|
|
||||||
extraNote: "Element Call needs a few extra ports (some UDP), and you’ll be shown exactly which when you enable it.",
|
|
||||||
})
|
|
||||||
+ '</div>';
|
+ '</div>';
|
||||||
|
|
||||||
relevantDomains.forEach(function(d) {
|
relevantDomains.forEach(function(d) {
|
||||||
@@ -382,20 +377,20 @@ async function loadStep3() {
|
|||||||
html += '<div class="onboarding-domain-group">';
|
html += '<div class="onboarding-domain-group">';
|
||||||
html += '<label class="onboarding-domain-label">' + escHtml(d.label) + '</label>';
|
html += '<label class="onboarding-domain-label">' + escHtml(d.label) + '</label>';
|
||||||
html += '<input class="onboarding-domain-input domain-field-input" type="text" id="domain-input-' + escHtml(d.name) + '" data-domain="' + escHtml(d.name) + '" placeholder="e.g. ' + escHtml(d.name) + '.yourdomain.com" value="' + escHtml(currentVal) + '" />';
|
html += '<input class="onboarding-domain-input domain-field-input" type="text" id="domain-input-' + escHtml(d.name) + '" data-domain="' + escHtml(d.name) + '" placeholder="e.g. ' + escHtml(d.name) + '.yourdomain.com" value="' + escHtml(currentVal) + '" />';
|
||||||
html += '<label class="onboarding-domain-label onboarding-domain-label--sub">Njal.la DDNS Curl Command</label>';
|
html += '<label class="onboarding-domain-label onboarding-domain-label--sub">Njal.la Update Command</label>';
|
||||||
html += '<input class="onboarding-domain-input domain-field-input" type="text" id="ddns-input-' + escHtml(d.name) + '" data-ddns="' + escHtml(d.name) + '" placeholder="curl "https://njal.la/update/?h=...&k=...&auto"" />';
|
html += '<input class="onboarding-domain-input domain-field-input" type="text" id="ddns-input-' + escHtml(d.name) + '" data-ddns="' + escHtml(d.name) + '" placeholder="curl "https://njal.la/update/?h=...&k=...&auto"" />';
|
||||||
html += '<p class="onboarding-hint" style="margin-top:4px;">ℹ Paste the curl URL from your Njal.la dashboard\'s Dynamic record</p>';
|
html += '<p class="onboarding-hint" style="margin-top:4px;">Paste the update command from Njal.la</p>';
|
||||||
html += '<button type="button" class="btn btn-primary onboarding-domain-save-btn" data-save-domain="' + escHtml(d.name) + '" style="align-self:flex-start;margin-top:8px;font-size:0.82rem;padding:6px 16px;">Save</button>';
|
html += '<button type="button" class="btn btn-primary onboarding-domain-save-btn" data-save-domain="' + escHtml(d.name) + '" style="align-self:flex-start;margin-top:8px;font-size:0.82rem;padding:6px 16px;">Save</button>';
|
||||||
html += '<span class="onboarding-domain-save-status" id="domain-save-status-' + escHtml(d.name) + '" style="font-size:0.82rem;min-height:1.2em;"></span>';
|
html += '<span class="onboarding-domain-save-status" id="domain-save-status-' + escHtml(d.name) + '" style="font-size:0.82rem;min-height:1.2em;"></span>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// SSL email section
|
// Contact email section
|
||||||
var emailVal = domainValues["sslemail"] || "";
|
var emailVal = domainValues["sslemail"] || "";
|
||||||
html += '<div class="onboarding-domain-group onboarding-domain-group--email">';
|
html += '<div class="onboarding-domain-group onboarding-domain-group--email">';
|
||||||
html += '<label class="onboarding-domain-label">📧 SSL Certificate Email</label>';
|
html += '<label class="onboarding-domain-label">📧 Email Address</label>';
|
||||||
html += '<p class="onboarding-hint onboarding-hint--inline">Let\'s Encrypt uses this for certificate expiry notifications.</p>';
|
html += '<p class="onboarding-hint onboarding-hint--inline">Used to send important notices about your services.</p>';
|
||||||
html += '<input class="onboarding-domain-input domain-field-input" type="email" id="ssl-email-input" placeholder="you@example.com" value="' + escHtml(emailVal) + '" />';
|
html += '<input class="onboarding-domain-input domain-field-input" type="email" id="ssl-email-input" placeholder="you@example.com" value="' + escHtml(emailVal) + '" />';
|
||||||
html += '<button type="button" class="btn btn-primary onboarding-domain-save-btn" data-save-email="true" style="align-self:flex-start;margin-top:8px;font-size:0.82rem;padding:6px 16px;">Save</button>';
|
html += '<button type="button" class="btn btn-primary onboarding-domain-save-btn" data-save-email="true" style="align-self:flex-start;margin-top:8px;font-size:0.82rem;padding:6px 16px;">Save</button>';
|
||||||
html += '<span class="onboarding-domain-save-status" id="domain-save-status-email" style="font-size:0.82rem;min-height:1.2em;"></span>';
|
html += '<span class="onboarding-domain-save-status" id="domain-save-status-email" style="font-size:0.82rem;min-height:1.2em;"></span>';
|
||||||
|
|||||||
@@ -197,22 +197,14 @@
|
|||||||
encrypted messaging, password management, cloud storage, website hosting, and more.
|
encrypted messaging, password management, cloud storage, website hosting, and more.
|
||||||
</p>
|
</p>
|
||||||
<div class="upgrade-info-box">
|
<div class="upgrade-info-box">
|
||||||
<p class="upgrade-info-title">⚠ What you should know:</p>
|
<p class="upgrade-info-title">Simple, guided setup:</p>
|
||||||
<ul class="upgrade-info-list">
|
<ul class="upgrade-info-list">
|
||||||
<li>You will need to purchase domains for your services — <a href="https://njal.la" target="_blank" rel="noopener noreferrer">Njal.la</a> is the only supported domain provider</li>
|
<li>Sovran_SystemsOS walks you through getting your domain from <a href="https://njal.la" target="_blank" rel="noopener noreferrer">Njal.la</a> and connecting your services</li>
|
||||||
<li>Some services require ports to be opened on your router</li>
|
<li>To make your services available outside your home, complete one router task: forward ports <strong>80 and 443</strong> to this computer</li>
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="upgrade-info-box">
|
|
||||||
<p class="upgrade-info-title">ℹ️ Good to know:</p>
|
|
||||||
<ul class="upgrade-info-list">
|
|
||||||
<li>Your services will be accessible via your home internet connection. Your approximate geographic area may be visible through DNS records — this is normal for all self-hosted services</li>
|
|
||||||
<li>Your Bitcoin node remains fully private over Tor</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<p class="support-desc">
|
<p class="support-desc">
|
||||||
<strong>Don't worry</strong> — the Hub will walk you through every step after the upgrade.
|
The Hub guides you through every step.
|
||||||
Domain setup, port forwarding, and configuration are all guided.
|
|
||||||
</p>
|
</p>
|
||||||
<p class="support-desc upgrade-rebuild-note">
|
<p class="support-desc upgrade-rebuild-note">
|
||||||
The system will rebuild after upgrading. This may take several minutes.
|
The system will rebuild after upgrading. This may take several minutes.
|
||||||
|
|||||||
@@ -123,10 +123,10 @@
|
|||||||
<div class="onboarding-panel" id="step-3" style="display:none">
|
<div class="onboarding-panel" id="step-3" style="display:none">
|
||||||
<div class="onboarding-step-header">
|
<div class="onboarding-step-header">
|
||||||
<span class="onboarding-step-icon">🌐</span>
|
<span class="onboarding-step-icon">🌐</span>
|
||||||
<h2 class="onboarding-step-title">Domain Configuration</h2>
|
<h2 class="onboarding-step-title">Connect Your Services</h2>
|
||||||
<p class="onboarding-step-desc">
|
<p class="onboarding-step-desc">
|
||||||
Sovran_SystemsOS uses <strong><a href="https://njal.la" target="_blank" style="color: var(--accent-color);">Njal.la</a></strong> for domains and Dynamic DNS, and your router needs ports <strong>80</strong> and <strong>443</strong> (TCP) forwarded to this computer.
|
Sovran_SystemsOS walks you through getting your domain from <strong><a href="https://njal.la" target="_blank" style="color: var(--accent-color);">Njal.la</a></strong> and connecting your services.
|
||||||
Everything you need — Njal.la account, Dynamic records, and the one router task — is laid out step by step below.
|
To make your services available outside your home, you’ll complete one router task: forward ports <strong>80</strong> and <strong>443</strong> to this computer.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="onboarding-card" id="step-3-body">
|
<div class="onboarding-card" id="step-3-body">
|
||||||
|
|||||||
+1
-35
@@ -423,40 +423,6 @@ class InstallerWindow(Adw.ApplicationWindow):
|
|||||||
sep.set_margin_end(40)
|
sep.set_margin_end(40)
|
||||||
outer.append(sep)
|
outer.append(sep)
|
||||||
|
|
||||||
notice_frame = Gtk.Frame()
|
|
||||||
notice_frame.add_css_class("card")
|
|
||||||
notice_frame.set_margin_start(40)
|
|
||||||
notice_frame.set_margin_end(40)
|
|
||||||
notice_frame.set_margin_top(20)
|
|
||||||
notice_frame.set_margin_bottom(4)
|
|
||||||
|
|
||||||
notice_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12)
|
|
||||||
notice_box.set_margin_top(12)
|
|
||||||
notice_box.set_margin_bottom(12)
|
|
||||||
notice_box.set_margin_start(16)
|
|
||||||
notice_box.set_margin_end(16)
|
|
||||||
|
|
||||||
notice_icon = symbolic_icon("dialog-information-symbolic")
|
|
||||||
notice_icon.set_valign(Gtk.Align.START)
|
|
||||||
notice_box.append(notice_icon)
|
|
||||||
|
|
||||||
notice_lbl = Gtk.Label()
|
|
||||||
notice_lbl.set_use_markup(True)
|
|
||||||
notice_lbl.set_wrap(True)
|
|
||||||
notice_lbl.set_xalign(0)
|
|
||||||
notice_lbl.set_halign(Gtk.Align.FILL)
|
|
||||||
notice_lbl.set_markup(
|
|
||||||
"<span weight='bold'>Heads up — Server + Desktop prerequisites</span>\n"
|
|
||||||
"• A domain or subdomain from <span weight='bold'>https://njal.la</span>\n"
|
|
||||||
"• The ability to open / forward ports on your router\n\n"
|
|
||||||
"Don't worry — after install, the onboarding wizard walks you through every step.\n"
|
|
||||||
"<span size='small'>Desktop Only and Node Only do not require a domain or port forwarding.</span>"
|
|
||||||
)
|
|
||||||
notice_box.append(notice_lbl)
|
|
||||||
|
|
||||||
notice_frame.set_child(notice_box)
|
|
||||||
outer.append(notice_frame)
|
|
||||||
|
|
||||||
if self.virtualization:
|
if self.virtualization:
|
||||||
vm_frame = Gtk.Frame()
|
vm_frame = Gtk.Frame()
|
||||||
vm_frame.add_css_class("card")
|
vm_frame.add_css_class("card")
|
||||||
@@ -505,7 +471,7 @@ class InstallerWindow(Adw.ApplicationWindow):
|
|||||||
# Role cards
|
# Role cards
|
||||||
roles = [
|
roles = [
|
||||||
("Server + Desktop",
|
("Server + Desktop",
|
||||||
"Full sovereign experience: beautiful desktop, your own cloud, secure messaging, Bitcoin node, and more.",
|
"Full sovereignty: host your own websites, cloud, chat, passwords, and Bitcoin services instead of relying on Big Tech. Sovran_SystemsOS walks you through getting your domain from Njal.la and connecting everything. One router task is required: forward ports 80 and 443 to this computer.",
|
||||||
"Server+Desktop"),
|
"Server+Desktop"),
|
||||||
("Desktop Only",
|
("Desktop Only",
|
||||||
"A beautiful, easy-to-use desktop without the background server applications.",
|
"A beautiful, easy-to-use desktop without the background server applications.",
|
||||||
|
|||||||
Reference in New Issue
Block a user