494 lines
29 KiB
HTML
494 lines
29 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en" class="h-full">
|
||
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta http-equiv="Permissions-Policy" content="clipboard-write=(self https://sftp.my-mc.link)">
|
||
<title>My-MC Panel</title>
|
||
<link rel="stylesheet" href="/css/styles.min.css?p=1">
|
||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.min.js"></script>
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||
<link href="https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" rel="stylesheet" />
|
||
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png">
|
||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
|
||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
|
||
<link rel="manifest" href="/favicon/site.webmanifest">
|
||
</head>
|
||
|
||
<body class="bg-gray-900 text-white overflow-x-hidden min-h-full flex flex-col">
|
||
<div id="app" class="flex-grow">
|
||
<div id="loginPage" class="hidden fixed inset-0 bg-gray-900 flex items-center justify-center">
|
||
<div class="bg-gray-800 p-8 rounded-lg shadow-lg w-full max-w-md">
|
||
<h2 class="text-2xl font-bold mb-6 text-center">My-MC Panel</h2>
|
||
<div class="mb-4">
|
||
<input id="loginApiKey" type="text" placeholder="Enter API Key"
|
||
class="bg-gray-700 px-4 py-2 rounded text-white w-full">
|
||
</div>
|
||
<button id="loginBtn" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded w-full">Login</button>
|
||
<p id="loginError" class="text-red-500 text-sm mt-2 hidden"></p>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="notificationContainer"></div>
|
||
|
||
<div id="tellModal" class="modal hidden">
|
||
<div class="modal-content">
|
||
<button class="modal-close">×</button>
|
||
<h2 class="text-xl font-semibold mb-4">Send Message to <span id="tellPlayerName"></span></h2>
|
||
<form id="tellForm">
|
||
<textarea id="tellMessage" placeholder="Enter your message"
|
||
class="bg-gray-700 px-4 py-2 rounded text-white w-full h-24 mb-4"></textarea>
|
||
<button type="submit" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded w-full">Send</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="giveModal" class="modal hidden">
|
||
<div class="modal-content">
|
||
<button class="modal-close">×</button>
|
||
<h2 class="text-xl font-semibold mb-4">Give Items to <span id="givePlayerName"></span></h2>
|
||
<form id="giveForm">
|
||
<div class="mb-4">
|
||
<label for="loadoutSelect" class="block text-sm font-medium mb-1">Select Loadout</label>
|
||
<select id="loadoutSelect" class="bg-gray-700 px-4 py-2 rounded text-white w-full">
|
||
<option value="custom">Custom</option>
|
||
<option value="starter">Starter Kit (Torches, Food)</option>
|
||
<option value="builder">Builder Kit (Stone, Wood)</option>
|
||
<option value="combat">Combat Kit (Sword, Armor)</option>
|
||
<option value="miner">Miner Kit (Pickaxe, Torches, Shovel)</option>
|
||
<option value="adventurer">Adventurer Kit (Bow, Arrows, Compass)</option>
|
||
<option value="alchemist">Alchemist Kit (Potions, Brewing Stand)</option>
|
||
<option value="enchanter">Enchanter Kit (Books, Lapis, Enchanting Table)</option>
|
||
<option value="farmer">Farmer Kit (Seeds, Hoe, Bone Meal)</option>
|
||
<option value="nether">Nether Survival Kit (Fire Resistance, Obsidian)</option>
|
||
<option value="end">End Prep Kit (Ender Pearls, Blaze Rods)</option>
|
||
</select>
|
||
</div>
|
||
<div id="customGiveFields" class="hidden mb-4">
|
||
<div id="itemList" class="space-y-2"></div>
|
||
<button type="button" id="addItemBtn" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded mt-2">Add
|
||
Item</button>
|
||
</div>
|
||
<button type="submit" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded w-full">Give</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="teleportModal" class="modal hidden">
|
||
<div class="modal-content">
|
||
<button class="modal-close">×</button>
|
||
<h2 class="text-xl font-semibold mb-4">Teleport <span id="teleportPlayerName"></span></h2>
|
||
<form id="teleportForm">
|
||
<div class="mb-4">
|
||
<label for="teleportDestination" class="block text-sm font-medium mb-1">Select Destination Player</label>
|
||
<select id="teleportDestination" class="bg-gray-700 px-4 py-2 rounded text-white w-full">
|
||
<!-- Options populated dynamically -->
|
||
</select>
|
||
</div>
|
||
<button type="submit" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded w-full">Teleport</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="effectModal" class="modal hidden">
|
||
<div class="modal-content">
|
||
<button class="modal-close">×</button>
|
||
<h2 class="text-xl font-semibold mb-4">Apply Effect to <span id="effectPlayerName"></span></h2>
|
||
<form id="effectForm">
|
||
<div class="mb-4">
|
||
<label for="effectSelect" class="block text-sm font-medium mb-1">Select Effect</label>
|
||
<select id="effectSelect" class="bg-gray-700 px-4 py-2 rounded text-white w-full">
|
||
<option value="speed:30:1">Speed (30s, Level 1)</option>
|
||
<option value="strength:30:1">Strength (30s, Level 1)</option>
|
||
<option value="regeneration:30:1">Regeneration (30s, Level 1)</option>
|
||
<option value="jump_boost:30:1">Jump Boost (30s, Level 1)</option>
|
||
<option value="invisibility:30:1">Invisibility (30s, Level 1)</option>
|
||
<option value="night_vision:60:1">Night Vision (60s, Level 1)</option>
|
||
<option value="fire_resistance:60:1">Fire Resistance (60s, Level 1)</option>
|
||
<option value="water_breathing:60:1">Water Breathing (60s, Level 1)</option>
|
||
</select>
|
||
</div>
|
||
<button type="submit" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded w-full">Apply Effect</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="editPropertiesModal" class="modal hidden">
|
||
<div class="modal-content">
|
||
<button class="modal-close">×</button>
|
||
<h2 class="text-xl font-semibold mb-4">Edit server.properties</h2>
|
||
<form id="editPropertiesForm" class="space-y-4">
|
||
<div id="propertiesFields" class="space-y-2"></div>
|
||
<button type="submit" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded w-full">Save</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="updateModsModal"
|
||
class="modal hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-2 sm:p-4">
|
||
<div
|
||
class="modal-content bg-gray-900 rounded-lg max-w-[95%] w-full sm:w-[90%] md:w-[85%] lg:w-[80%] mx-auto flex flex-col max-h-[95vh]">
|
||
<div class="flex justify-between items-center p-4 border-b">
|
||
<h2 class="text-xl font-semibold text-white">Mod Update Output</h2>
|
||
<button class="modal-close text-2xl font-bold text-white">×</button>
|
||
</div>
|
||
<pre id="updateModsOutput"
|
||
class="flex-1 p-4 text-white text-sm max-h-[calc(95vh-10rem)] overflow-y-auto overflow-x-auto whitespace-pre-wrap break-words leading-relaxed"></pre>
|
||
<div class="p-4 border-t">
|
||
<button id="closeUpdateModsBtn"
|
||
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded w-full">Close</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<nav class="bg-gray-800 p-4 shadow-lg">
|
||
<div class="container mx-auto flex justify-between items-center">
|
||
<h1 class="text-2xl font-bold">My-MC Panel</h1>
|
||
<div class="flex space-x-4">
|
||
<button id="refresh" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded">Refresh</button>
|
||
<button id="backupBtn" class="bg-purple-600 hover:bg-purple-700 px-4 py-2 rounded">Backup</button>
|
||
<div id="authControls">
|
||
<input id="apiKey" type="text" placeholder="Enter API Key" class="bg-gray-700 px-4 py-2 rounded text-white">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<main id="mainContent" class="container mx-auto p-6">
|
||
<div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-6" data-section="server-status">
|
||
<h2 class="text-xl font-semibold mb-4">Server Status</h2>
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||
<div>
|
||
<p><strong>User:</strong> <span id="user">Loading...</span></p>
|
||
<p><strong>Key Expiry:</strong> <span id="keyExpiry">Loading...</span></p>
|
||
<p><strong>Status:</strong> <span id="serverStatus">Loading...</span></p>
|
||
</div>
|
||
<div class="flex space-x-4 justify-center">
|
||
<div class="text-center">
|
||
<canvas id="memoryMeter" width="150" height="150"></canvas>
|
||
<p class="text-sm mt-2"><b>Memory Usage</b></p>
|
||
<p id="memoryPercent" class="text-lg font-bold">0%</p>
|
||
</div>
|
||
<div class="text-center">
|
||
<canvas id="cpuMeter" width="150" height="150"></canvas>
|
||
<p class="text-sm mt-2"><b>CPU Usage</b></p>
|
||
<p id="cpuPercent" class="text-lg font-bold">0%</p>
|
||
</div>
|
||
</div>
|
||
<div class="flex flex-wrap space-x-2 justify-end items-center">
|
||
<div class="flex space-x-2">
|
||
<button id="startBtn"
|
||
class="bg-green-600 hover:bg-green-700 rounded font-medium control-btn">Start</button>
|
||
<button id="stopBtn" class="bg-red-600 hover:bg-red-700 rounded font-medium control-btn">Stop</button>
|
||
<button id="restartBtn"
|
||
class="bg-yellow-600 hover:bg-yellow-700 rounded font-medium control-btn">Restart</button>
|
||
</div>
|
||
<button id="editPropertiesBtn"
|
||
class="bg-purple-600 hover:bg-purple-700 px-4 py-2 rounded control-btn w-full mt-2">Edit Server
|
||
Properties</button>
|
||
<button id="updateModsBtn"
|
||
class="bg-purple-600 hover:bg-purple-700 px-4 py-2 rounded control-btn w-full mt-2">Update Mods</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-6">
|
||
<h2 class="text-xl font-semibold mb-4">Player Management</h2>
|
||
<div class="mb-4"></div>
|
||
<p><strong>Connected Players:</strong><br> <span id="playerList">Loading...</span></p>
|
||
</div>
|
||
|
||
<div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-6">
|
||
<h2 class="text-xl font-semibold mb-4">Server Logs</h2>
|
||
<div id="dockerLogsTerminal" class="mt-4"></div>
|
||
</div>
|
||
|
||
<div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-6">
|
||
<h2 class="text-xl font-semibold mb-4">Server Console</h2>
|
||
<form id="consoleForm" onsubmit="event.preventDefault(); sendConsoleCommand();">
|
||
<input id="consoleInput" type="text" placeholder="Enter RCON Command (Hit Enter To Submit)"
|
||
class="bg-gray-700 px-4 py-2 rounded text-white w-full mb-2">
|
||
<button id="sendConsole" type="submit" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded"
|
||
style="display: none;">Send</button>
|
||
</form>
|
||
<pre id="consoleOutput" class="bg-gray-900 p-4 rounded mt-4 h-48 overflow-y-auto"></pre>
|
||
</div>
|
||
|
||
<div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-6" id="sftpBrowserSection" style="display: none;">
|
||
<div class="flex justify-between items-baseline mb-4">
|
||
<h2 class="text-xl font-semibold">SFTP Browser</h2>
|
||
<button id="sftpBtn" class="px-3 py-1 rounded text-sm flex items-center space-x-1"
|
||
style="background-color: #121724; color: #ffffff;">
|
||
<i class="fas fa-sync-alt" style="color: #121724;"></i>
|
||
<span>Refresh SFTP</span>
|
||
</button>
|
||
</div>
|
||
<iframe id="sftpIframe" class="w-full rounded" style="height: 650px; min-height: 650px;"
|
||
sandbox="allow-same-origin allow-scripts allow-downloads allow-popups"
|
||
allow="clipboard-read; clipboard-write"></iframe>
|
||
</div>
|
||
|
||
<div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-6">
|
||
<h2 class="text-xl font-semibold mb-4">Mod Management</h2>
|
||
<form id="modSearchForm" onsubmit="event.preventDefault(); searchMods(1);">
|
||
<div class="mb-4 flex space-x-2">
|
||
<input id="modSearch" type="text" placeholder="Search Mods (Hit Enter To Submit)"
|
||
class="bg-gray-700 px-4 py-2 rounded text-white flex-grow">
|
||
<button id="searchBtn" type="submit" class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded"
|
||
style="display: none;">Search</button>
|
||
<button id="closeSearchBtn" type="button"
|
||
class="bg-gray-600 hover:bg-gray-700 px-4 py-2 rounded hidden">Close</button>
|
||
</div>
|
||
</form>
|
||
<div id="modResults" class="grid grid-cols-1 md:grid-cols-2 gap-4"></div>
|
||
<div id="pagination" class="mt-4 flex justify-center space-x-2"></div>
|
||
<h3 class="text-lg font-semibold mt-4">Installed Mods</h3>
|
||
<div class="mb-4 flex space-x-2">
|
||
<input id="modListSearch" type="text" placeholder="Search Installed Mods"
|
||
class="bg-gray-700 px-4 py-2 rounded text-white flex-grow">
|
||
<button id="clearModListSearch" type="button"
|
||
class="bg-gray-600 hover:bg-gray-700 px-4 py-2 rounded hidden">Clear</button>
|
||
</div>
|
||
<div id="modList" class="mt-2 grid grid-cols-1 md:grid-cols-2 gap-4"></div>
|
||
<div id="modListPagination" class="mt-4 flex justify-center space-x-2"></div>
|
||
</div>
|
||
|
||
<div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-6">
|
||
<h2 class="text-xl font-semibold mb-4">Server Links</h2>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<p><strong>Advanced Log URL:</strong> <a id="logUrl" href="#" class="text-blue-400"
|
||
target="_blank">Loading...</a></p>
|
||
<p><strong>Website URL:</strong> <a id="websiteUrl" href="#" class="text-blue-400"
|
||
target="_blank">Loading...</a></p>
|
||
<p><strong>BlueMap URL:</strong> <a id="mapUrl" href="#" class="text-blue-400" target="_blank">Loading...</a>
|
||
</p>
|
||
<div>
|
||
<p><strong>Connection Link:</strong> <span id="myLink">Link Not Created</span> <span
|
||
id="connectionStatus"></span></p>
|
||
<button id="generateMyLinkBtn" class="bg-blue-600 hover:bg-blue-700 px-4 py-1 rounded mt-2">Generate
|
||
Connection Link</button>
|
||
</div>
|
||
<div>
|
||
<p><strong>Geyser Link:</strong> <span id="geyserLink">Link Not Created</span> <span
|
||
id="geyserStatus"></span></p>
|
||
<button id="generateGeyserLinkBtn" class="bg-blue-600 hover:bg-blue-700 px-4 py-1 rounded mt-2">Generate
|
||
Geyser Link</button>
|
||
</div>
|
||
<div>
|
||
<p><strong>SFTP Link:</strong> <span id="sftpLink">Link Not Created</span> <span id="sftpStatus"></span></p>
|
||
<button id="generateSftpLinkBtn" class="bg-blue-600 hover:bg-blue-700 px-4 py-1 rounded mt-2">Generate SFTP
|
||
Link</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bg-gray-800 p-6 rounded-lg shadow-lg mb-6">
|
||
<div class="flex items-center justify-between mb-4">
|
||
<h2 class="text-xl font-semibold text-white">Holesail Keys</h2>
|
||
<button id="toggleTutorial" class="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md transition duration-200">Tutorial</button>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
||
<div class="flex items-center bg-gray-700 p-3 rounded-md">
|
||
<div class="flex-grow">
|
||
<p class="text-gray-300"><strong>Minecraft Key:</strong></p>
|
||
<p class="text-gray-100 break-all" id="holesailHash">Not Loaded</p>
|
||
<p class="text-sm text-gray-400">Port: 127.0.0.1:25565</p>
|
||
</div>
|
||
<button onclick="navigator.clipboard.writeText(document.getElementById('holesailHash').textContent)" class="ml-2 text-gray-300 hover:text-white" title="Copy">
|
||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<div class="flex items-center bg-gray-700 p-3 rounded-md">
|
||
<div class="flex-grow">
|
||
<p class="text-gray-300"><strong>Geyser Key:</strong></p>
|
||
<p class="text-gray-100 break-all" id="geyserHash">Not Loaded</p>
|
||
<p class="text-sm text-gray-400">Port: 127.0.0.1:19132</p>
|
||
</div>
|
||
<button onclick="navigator.clipboard.writeText(document.getElementById('geyserHash').textContent)" class="ml-2 text-gray-300 hover:text-white" title="Copy">
|
||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<div class="flex items-center bg-gray-700 p-3 rounded-md">
|
||
<div class="flex-grow">
|
||
<p class="text-gray-300"><strong>SFTP Key:</strong></p>
|
||
<p class="text-gray-100 break-all" id="sftpHash">Not Loaded</p>
|
||
<p class="text-sm text-gray-400">Port: 127.0.0.1:22</p>
|
||
</div>
|
||
<button onclick="navigator.clipboard.writeText(document.getElementById('sftpHash').textContent)" class="ml-2 text-gray-300 hover:text-white" title="Copy">
|
||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="tutorialSection" class="hidden">
|
||
<div class="bg-gray-700 p-6 rounded-xl mb-6 border border-gray-600">
|
||
<h3 class="text-xl font-bold mb-4 text-white border-b border-gray-500 pb-2">What is Holesail.io?</h3>
|
||
<p class="text-gray-200 text-base leading-relaxed mb-4">
|
||
<a href="https://holesail.io" target="_blank" class="text-blue-400 hover:underline font-medium">Holesail.io</a> is an open-source, peer-to-peer networking tool that creates secure, encrypted tunnels that bypass network restrictions, firewalls, and NAT.<BR>It exposes your local network to the internet without needing port forwarding, static IPs, or Dynamic DNS, acting as a versatile tunneling and reverse proxy solution.
|
||
</p>
|
||
<div class="mb-4">
|
||
<p class="text-gray-200 font-semibold mb-2">With Holesail, you can:</p>
|
||
<ul class="list-disc pl-6 space-y-1 text-gray-200 text-base">
|
||
<li>* Access machines over the internet securely.</li>
|
||
<li>* Share locally running servers, websites, or AI models with other ports/services.</li>
|
||
<li>* Transfer files and folders remotely without bandwidth or size limits.</li>
|
||
<li>* Play LAN games like Minecraft with friends remotely.</li>
|
||
<li>* Secure SSH servers by blocking IP access and using Holesail for connections.</li>
|
||
<li>* Built for ANY application, Holesail supports both the TCP and UDP Protocols nativly.</li>
|
||
<li>* Expose single ports to the peer-to-peer network, unlike VPNs you never expose your entire local network.</li>
|
||
<li>* And so much more! With Holesail, the possiblities are endless!</li>
|
||
|
||
|
||
</ul>
|
||
</div>
|
||
<p class="text-gray-200 text-base leading-relaxed">
|
||
Built with security in mind, Holesail ensures all data is encrypted and never touches third-party servers.<BR>Connections are truly peer-to-peer, accessible only to those with whom you share your private key, providing both ease of use and robust security.<BR>Other peers cannot detect your activity or services.<BR>As an open-source tool, Holesail enables third-party services to integrate it, enhancing their security and connectivity.
|
||
</p>
|
||
<p class="text-gray-200 text-base leading-relaxed">
|
||
<BR>Your Public My-MC Ports are Holesail connections hosted on a separate server, not our Minecraft host.<BR>They use the same keys from the tutorial below. We hook 'em up at our jump host to go public. Pretty dope, right?
|
||
</p>
|
||
</div>
|
||
|
||
<div class="bg-gray-700 p-4 rounded-md mb-6">
|
||
<h3 class="text-lg font-semibold mb-3 text-white">How to Use Holesail Keys</h3>
|
||
<ol class="list-decimal list-inside space-y-2 text-gray-300">
|
||
<li>Ensure <a href="https://nodejs.org/" target="_blank" class="text-blue-400 hover:underline">Node.js</a> is installed on your system.</li>
|
||
<li>Install Holesail by running:
|
||
<pre class="bg-gray-800 p-2 rounded mt-1 text-sm">npm i holesail@2.1.0</pre>
|
||
</li>
|
||
<li>Connect to a key using the appropriate command:
|
||
<ul class="list-disc list-inside ml-4 mt-1">
|
||
<li>For Minecraft Key (e.g., Minecraft server):
|
||
<pre class="bg-gray-800 p-2 rounded mt-1 text-sm">holesail <span id="tutorialHolesailHash">Not Loaded</span></pre>
|
||
</li>
|
||
<li>For Geyser key (e.g., cross-platform Minecraft):
|
||
<pre class="bg-gray-800 p-2 rounded mt-1 text-sm">holesail <span id="tutorialGeyserHash">Not Loaded</span></pre>
|
||
</li>
|
||
<li>For SFTP key (e.g., file transfer):
|
||
<pre class="bg-gray-800 p-2 rounded mt-1 text-sm">holesail <span id="tutorialSftpHash">Not Loaded</span></pre>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li>Holesail will confirm the connection. Example output for your Minecraft server:
|
||
<pre class="bg-gray-800 p-2 rounded mt-1 text-sm">
|
||
~ ❯ holesail <span id="tutorialHolesailHashOutput">Not Loaded</span>
|
||
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||
| |
|
||
| |
|
||
| Holesail TCP Client Started ⛵️ |
|
||
| Connection Mode: Private Connection String |
|
||
| Access application on http://127.0.0.1:25565/ |
|
||
| Connected to key: <span id="tutorialHolesailHashOutput2">Not Loaded</span> |
|
||
| NOTE: TREAT PRIVATE CONNECTION STRINGS HOW YOU WOULD TREAT SSH KEY, DO NOT SHARE IT WITH ANYONE YOU DO NOT TRUST |
|
||
| |
|
||
| |
|
||
| |
|
||
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
</pre>
|
||
</li>
|
||
<li>To share the port over your internet IP as an open port, add the <code class="bg-gray-800 px-1 rounded">--host 0.0.0.0</code> switch:
|
||
<pre class="bg-gray-800 p-2 rounded mt-1 text-sm">holesail <span id="tutorialHolesailHashHost">Not Loaded</span> --host 0.0.0.0</pre>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
|
||
<div class="bg-gray-700 p-4 rounded-md">
|
||
<h3 class="text-lg font-semibold mb-3 text-white">Share with Friends</h3>
|
||
<p class="text-gray-300 mb-3">
|
||
Share this tutorial with your friends so they can connect to your Minecraft server or other services on their own localhosts!<BR>With Holesail, no public IPs are needed! Everything stays secure and peer-to-peer!
|
||
</p>
|
||
<button id="copyTutorial" class="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md transition duration-200">Copy Tutorial</button>
|
||
<p id="copyNotification" class="hidden text-green-400 mt-2 text-sm">Tutorial copied to clipboard!</p>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Function to update tutorial spans when key display spans are populated
|
||
function updateTutorialSpans() {
|
||
const holesailHash = document.getElementById('holesailHash').textContent;
|
||
const geyserHash = document.getElementById('geyserHash').textContent;
|
||
const sftpHash = document.getElementById('sftpHash').textContent;
|
||
|
||
document.getElementById('tutorialHolesailHash').textContent = holesailHash;
|
||
document.getElementById('tutorialGeyserHash').textContent = geyserHash;
|
||
document.getElementById('tutorialSftpHash').textContent = sftpHash;
|
||
document.getElementById('tutorialHolesailHashOutput').textContent = holesailHash;
|
||
document.getElementById('tutorialHolesailHashOutput2').textContent = holesailHash;
|
||
document.getElementById('tutorialHolesailHashHost').textContent = holesailHash;
|
||
}
|
||
|
||
// Run initially
|
||
updateTutorialSpans();
|
||
|
||
// Observe changes to key display spans
|
||
const observer = new MutationObserver(updateTutorialSpans);
|
||
document.querySelectorAll('#holesailHash, #geyserHash, #sftpHash').forEach(span => {
|
||
observer.observe(span, { childList: true, characterData: true, subtree: true });
|
||
});
|
||
|
||
// Toggle tutorial section visibility
|
||
document.getElementById('toggleTutorial').addEventListener('click', () => {
|
||
const tutorialSection = document.getElementById('tutorialSection');
|
||
tutorialSection.classList.toggle('hidden');
|
||
});
|
||
|
||
// Copy summarized tutorial in Markdown and show success message
|
||
document.getElementById('copyTutorial').addEventListener('click', () => {
|
||
const holesailHash = document.getElementById('holesailHash').textContent;
|
||
const markdownTutorial = `# Join My Minecraft Server with Holesail!
|
||
|
||
Holesail is a secure, peer-to-peer tool that lets you connect to my server without public IPs.
|
||
|
||
1. **Install Node.js**: Download and install from [nodejs.org](https://nodejs.org/).
|
||
2. **Install Holesail**: Open a terminal and run:
|
||
\`\`\`bash
|
||
npm i holesail@2.1.0
|
||
\`\`\`
|
||
3. **Connect to the server**: Use this command with the key:
|
||
\`\`\`bash
|
||
holesail ${holesailHash}
|
||
\`\`\`
|
||
4. **Join in Minecraft**: Once Holesail confirms the connection, connect to \`127.0.0.1:25565\` in Minecraft.
|
||
|
||
**Note**: Keep the key private, like an SSH key. No public IPs needed—it's all peer-to-peer!`;
|
||
navigator.clipboard.writeText(markdownTutorial);
|
||
|
||
// Show success message
|
||
const notification = document.getElementById('copyNotification');
|
||
notification.classList.remove('hidden');
|
||
|
||
// Hide success message after 3 seconds
|
||
setTimeout(() => {
|
||
notification.classList.add('hidden');
|
||
}, 3000);
|
||
});
|
||
</script>
|
||
</div>
|
||
|
||
</main>
|
||
|
||
<footer class="bg-gray-800 py-4">
|
||
<div class="container mx-auto px-6 text-center">
|
||
<p class="text-gray-400 text-sm">
|
||
© 2025 My-MC.Link. All rights reserved.<br>
|
||
<a href="https://raven-scott.fyi" target="_blank" class="text-blue-400 hover:text-blue-500">Made with ❤️ by
|
||
SNXRaven</a> | <a href="https://git.ssh.surf/hypermc/panel" target="_blank"
|
||
class="text-blue-400 hover:text-blue-500">Source Code</a>
|
||
</p>
|
||
</div>
|
||
</footer>
|
||
</div>
|
||
|
||
<script src="js/app.js"></script>
|
||
</body>
|
||
|
||
</html> |