diff --git a/.gitignore b/.gitignore index 30ae2d3..92aa930 100644 --- a/.gitignore +++ b/.gitignore @@ -153,3 +153,5 @@ Temporary Items /**/*.Web.UI/Umbraco/Data baseline.json **/wwwroot/scripts/variables.js + +*.pem diff --git a/cleanup.js b/cleanup.js index 1273f07..2d74716 100644 --- a/cleanup.js +++ b/cleanup.js @@ -52,13 +52,15 @@ async function main() { let hostsContent = fs.readFileSync(hostsPath, "utf8"); const originalContent = hostsContent; - // Remove entries for both domains + // Remove entries for both domains (match exact host entries) + const wwwEntry = `127.0.0.1 ${domainWithWww}`; + const nonWwwEntry = `127.0.0.1 ${domainWithoutWww}`; const lines = hostsContent.split("\n"); const filteredLines = lines.filter((line) => { const trimmedLine = line.trim(); - return !( - trimmedLine.includes(domainWithWww) || - trimmedLine.includes(domainWithoutWww) + return ( + trimmedLine !== wwwEntry && + trimmedLine !== nonWwwEntry ); }); @@ -127,16 +129,18 @@ async function main() { const certFile = path.join(sslDir, `${domainWithWww}.pem`); const keyFile = path.join(sslDir, `${domainWithWww}-key.pem`); + let certsFound = false; if (fs.existsSync(certFile)) { fs.unlinkSync(certFile); console.log(` āœ“ Removed ${domainWithWww}.pem`); + certsFound = true; } if (fs.existsSync(keyFile)) { fs.unlinkSync(keyFile); console.log(` āœ“ Removed ${domainWithWww}-key.pem`); + certsFound = true; } - - if (!fs.existsSync(certFile) && !fs.existsSync(keyFile)) { + if (!certsFound) { console.log(" āœ“ No certificates found"); } } catch (error) { diff --git a/docker-compose.yml b/docker-compose.yml index e4adf3b..b4803b1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3.9" - services: reverse-proxy: image: nginx:latest diff --git a/setup.js b/setup.js index a2b0998..c8c8bc2 100644 --- a/setup.js +++ b/setup.js @@ -14,6 +14,49 @@ function question(query) { return new Promise((resolve) => rl.question(query, resolve)); } +function checkWindowsPortsBlocked(ports) { + const blocked = []; + for (const port of ports) { + try { + // netstat output contains lines like " TCP 0.0.0.0:80 ..." + const output = execSync(`netstat -an`, { encoding: "utf8" }); + // Also check excluded port ranges reserved by http.sys + let reserved = ""; + try { + reserved = execSync( + `netsh int ipv4 show excludedportrange protocol=tcp`, + { encoding: "utf8" } + ); + } catch (_) {} + + const portInUse = output.split("\n").some((line) => { + const m = line.match(/TCP\s+[\d.:*]+:(\d+)\s/); + return m ? m[1] === String(port) : false; + }); + + // Check if port falls within an http.sys excluded range + let portReserved = false; + if (reserved) { + const rangeRegex = /(\d+)\s+(\d+)/g; + let m; + while ((m = rangeRegex.exec(reserved)) !== null) { + const start = parseInt(m[1], 10); + const num = parseInt(m[2], 10); + if (port >= start && port < start + num) { + portReserved = true; + break; + } + } + } + + if (portInUse || portReserved) blocked.push(port); + } catch (_) { + // If we can't check, assume it's fine + } + } + return blocked; +} + async function main() { console.log("šŸš€ Proxy Setup Script\n"); @@ -23,9 +66,10 @@ async function main() { const domainWithWww = domain.startsWith("www.") ? domain : `www.${domain}`; // Step 2: Get proxy port - const proxyPort = await question( - "Enter the port to proxy to (e.g., 44314): " + const proxyPortInput = await question( + "Enter the port to proxy to (default: 44314): " ); + const proxyPort = proxyPortInput.trim() || "44314"; console.log("\nšŸ“‹ Configuration:"); console.log(` Domain (with www): ${domainWithWww}`); @@ -129,11 +173,11 @@ http { const nonWwwEntry = `127.0.0.1 ${domainWithoutWww}`; let needsUpdate = false; - if (!hostsContent.includes(domainWithWww)) { + if (!hostsContent.includes(wwwEntry)) { hostsContent += `\n${wwwEntry}`; needsUpdate = true; } - if (!hostsContent.includes(domainWithoutWww)) { + if (!hostsContent.includes(nonWwwEntry)) { hostsContent += `\n${nonWwwEntry}`; needsUpdate = true; } @@ -181,6 +225,47 @@ http { console.log("āœ… Setup complete!\n"); const startDocker = await question("Start Docker Compose now? (y/n): "); if (startDocker.toLowerCase() === "y") { + // Check if required ports are available on Windows + if (process.platform === "win32") { + const portsBlocked = checkWindowsPortsBlocked([80, 443]); + if (portsBlocked.length > 0) { + console.log( + `\nāš ļø Port(s) ${portsBlocked.join(", ")} are not available.` + ); + console.log( + " On Windows, this is usually caused by the HTTP.sys service (IIS, Hyper-V, etc.)." + ); + const freePorts = await question( + " Attempt to free port(s) automatically? (runs 'net stop http /y' as admin) (y/n): " + ); + if (freePorts.toLowerCase() === "y") { + try { + execSync( + `powershell -Command "Start-Process cmd -Verb RunAs -ArgumentList '/c net stop http /y' -Wait"`, + { stdio: "inherit" } + ); + console.log(" āœ“ HTTP.sys service stopped"); + } catch (error) { + console.error( + " āœ— Could not stop HTTP.sys. Try running manually as admin:" + ); + console.log(" net stop http /y"); + console.log('\nRun "docker compose up" when ready.'); + rl.close(); + return; + } + } else { + console.log( + "\n To free port 80/443, run as Administrator:" + ); + console.log(" net stop http /y"); + console.log('\nRun "docker compose up" when ready.'); + rl.close(); + return; + } + } + } + console.log("\n🐳 Starting Docker Compose...\n"); try { execSync("docker compose up", { stdio: "inherit" });