Upload files to "/"
This commit is contained in:
140
README.md
Normal file
140
README.md
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
# Wake on LAN Web Interface – Full Setup Guide
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Debian-based Linux system or Raspberry Pi
|
||||||
|
- Git
|
||||||
|
- Node.js (LTS)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Install Git and Node.js (Debian / Raspberry Pi)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update package index
|
||||||
|
sudo apt update
|
||||||
|
|
||||||
|
# Install Git and curl
|
||||||
|
sudo apt install git curl -y
|
||||||
|
|
||||||
|
# Install Node.js (LTS version)
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
|
||||||
|
sudo apt install -y nodejs
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify installation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node -v
|
||||||
|
npm -v
|
||||||
|
git --version
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Clone the Repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.luisk.de/luis/wol-server.git
|
||||||
|
cd wol-server
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Edit the HTML File and package.json
|
||||||
|
|
||||||
|
Open `index.html` and modify the marked lines:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nano index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
Look for comments like:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- CHANGE THIS -->
|
||||||
|
```
|
||||||
|
|
||||||
|
Adjust the MAC addresses, hostnames, etc.
|
||||||
|
|
||||||
|
Also change in package.json the port in scripts: server
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Install Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Start the Server Manually (For Testing)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run server
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now access the interface via your browser on your specified port (e.g., `http://<your-server-ip>:3000`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Auto-Start with systemd (Linux)
|
||||||
|
|
||||||
|
To automatically run the server at boot, create a systemd service.
|
||||||
|
|
||||||
|
### a) Create the Service File
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo nano /etc/systemd/system/wol-server.service
|
||||||
|
```
|
||||||
|
|
||||||
|
Paste the following:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=Wake on LAN Web Interface
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
WorkingDirectory=/home/pi/wol-server
|
||||||
|
ExecStart=/usr/bin/npm run server
|
||||||
|
Restart=always
|
||||||
|
User=pi
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
> 🔧 Replace:
|
||||||
|
> - `/home/pi/wol-server` with the actual path to your project
|
||||||
|
> - `User=pi` with your actual system username
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### b) Enable and Start the Service
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl daemon-reexec
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable wol-server
|
||||||
|
sudo systemctl start wol-server
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### c) Check Service Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl status wol-server
|
||||||
|
```
|
||||||
|
|
||||||
|
You should see:
|
||||||
|
|
||||||
|
```
|
||||||
|
Active: active (running)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
✅ Done! Your Wake on LAN Web Interface is now installed and set to run automatically on system startup.
|
||||||
122
index.html
Normal file
122
index.html
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Wake-on-LAN Interface</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <!-- add this -->
|
||||||
|
<!-- Desktop styles: only for screens wider than 768px -->
|
||||||
|
<link rel="stylesheet" href="desktop.css" media="screen and (min-width: 768px)">
|
||||||
|
<!-- Mobile styles: only for screens up to 767px -->
|
||||||
|
<link rel="stylesheet" href="mobile.css" media="screen and (max-width: 767px)">
|
||||||
|
<!-- Icon & Manifest -->
|
||||||
|
<link rel="icon" type="image/png" href="/icon/favicon-96x96.png" sizes="96x96" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/icon/favicon.svg" />
|
||||||
|
<link rel="shortcut icon" href="/icon/favicon.ico" />
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="/icon/apple-touch-icon.png" />
|
||||||
|
<meta name="apple-mobile-web-app-title" content="WOL-Server" />
|
||||||
|
<link rel="manifest" href="/icon/site.webmanifest" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Wake-on-LAN Interface</h1>
|
||||||
|
<div class="button-group">
|
||||||
|
<button id="wake" type="button">Wake Server</button>
|
||||||
|
<button id="ping" type="button">Ping Server</button>
|
||||||
|
</div>
|
||||||
|
<div class="status-container">
|
||||||
|
Status:
|
||||||
|
<span id="status" class="status-text">Ready</span>
|
||||||
|
<svg id="spinner" class="spinner" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" >
|
||||||
|
<circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="4"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const status = document.getElementById('status');
|
||||||
|
const spinner = document.getElementById('spinner');
|
||||||
|
|
||||||
|
function showSpinner() {
|
||||||
|
spinner.classList.add('visible');
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideSpinner() {
|
||||||
|
spinner.classList.remove('visible');
|
||||||
|
}
|
||||||
|
|
||||||
|
const ping = () => {
|
||||||
|
showSpinner();
|
||||||
|
status.innerText = 'pinging';
|
||||||
|
status.className = "status-text";
|
||||||
|
fetch('/ping?host=192.168.178.41') // also here
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if(data.message == true){
|
||||||
|
status.innerText = 'server is active';
|
||||||
|
status.className = "status-text green";
|
||||||
|
} else {
|
||||||
|
status.innerText = 'server is dead';
|
||||||
|
status.className = "status-text red";
|
||||||
|
}
|
||||||
|
hideSpinner();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
status.innerText = 'failed, unknown error';
|
||||||
|
status.className = "status-text red";
|
||||||
|
hideSpinner();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('wake').addEventListener('click', () => {
|
||||||
|
showSpinner();
|
||||||
|
fetch('/wake?mac=9C:7B:EF:A7:F2:F6') // replace with the MAC-Address of your PC
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
status.innerText = 'waiting for boot';
|
||||||
|
status.className = "status-text";
|
||||||
|
|
||||||
|
setTimeout(async () => {
|
||||||
|
status.innerText = 'pinging';
|
||||||
|
let booted = false;
|
||||||
|
let trys = 0;
|
||||||
|
while (!booted && trys < 10) {
|
||||||
|
trys++;
|
||||||
|
await fetch('/ping?host=192.168.178.41') // set static IP in your Router to make Ping work, then enter IP-Address
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status == 'success' && data.message === true) {
|
||||||
|
booted = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
status.innerText = 'failed, unknown error';
|
||||||
|
status.className = "status-text red";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (booted) {
|
||||||
|
status.innerText = 'booted';
|
||||||
|
status.className = "status-text green";
|
||||||
|
} else {
|
||||||
|
status.innerText = 'failed, did not respond to ping';
|
||||||
|
status.className = "status-text red";
|
||||||
|
}
|
||||||
|
hideSpinner();
|
||||||
|
}, 25000);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
status.innerText = 'failed, unknown error';
|
||||||
|
status.className = "status-text red";
|
||||||
|
hideSpinner();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('ping').addEventListener('click', ping);
|
||||||
|
ping();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
48
index.js
Normal file
48
index.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
const wol = require('wakeonlan');
|
||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
const path = require('path');
|
||||||
|
const ping = require('ping')
|
||||||
|
|
||||||
|
const port = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
// Middleware
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
app.use(express.static('public'));
|
||||||
|
|
||||||
|
// Serve HTML
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.sendFile(path.join(__dirname, 'index.html'));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wake endpoint
|
||||||
|
app.get('/wake', (req, res) => {
|
||||||
|
const mac = req.query.mac;
|
||||||
|
|
||||||
|
if (mac && mac !== '') {
|
||||||
|
wol(mac)
|
||||||
|
.then(() => {
|
||||||
|
res.json({ status: 'success', message: `WOL packet sent to ${mac}` });
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
res.json({ status: 'error', message: err.message });
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.json({ status: 'failed', message: 'No MAC address specified' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/ping', (req, res) => {
|
||||||
|
const host = req.query.host
|
||||||
|
if(host && host != ''){
|
||||||
|
ping.sys.probe(host, (isAlive) => {
|
||||||
|
res.json({ status: 'success', message: isAlive })
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
res.json({ status: 'failed', message: 'No Host address specified' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
app.listen(port);
|
||||||
2005
package-lock.json
generated
Normal file
2005
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
package.json
Normal file
24
package.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "wol",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "WakeOnLan for my Server",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node index.js",
|
||||||
|
"tailwind:init": "tailwindcss init",
|
||||||
|
"server": "PORT=3002 node index.js"
|
||||||
|
},
|
||||||
|
"author": "Luis",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@tailwindcss/cli": "^4.1.11",
|
||||||
|
"body-parser": "^2.2.0",
|
||||||
|
"express": "^5.1.0",
|
||||||
|
"path": "^0.12.7",
|
||||||
|
"ping": "^0.4.4",
|
||||||
|
"wakeonlan": "^0.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"tailwindcss": "^4.1.11"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user