VPN node management daemon for the DeVPN decentralized P2P VPN network powered by TON blockchain.
✅ On-chain & Off-chain Registration - Register to Backend API and NodeRegistry contract ✅ Session Monitoring - Poll SessionManager for assigned sessions ✅ WireGuard Management - Mock peer add/remove (production-ready structure) ✅ HTTP API - REST API for Backend to manage peers ✅ Heartbeat - Health status reporting to Backend ✅ Blockchain Integration - Query TON testnet contracts
src/
├── index.js # Main daemon orchestrator
├── config.js # Configuration loader
├── services/
│ ├── registration.js # Node registration (on-chain + off-chain)
│ ├── blockchain.js # TON client & contract queries
│ ├── wireguard.js # WireGuard keypair & peer management (mocked)
│ ├── sessionMonitor.js # Session polling & detection
│ ├── httpServer.js # Express API (:8080)
│ └── heartbeat.js # Health reporting (endpoint not ready)
└── utils/
└── logger.js # Winston logger
pnpm installEdit .env and set:
# Update contract addresses
NODE_REGISTRY_ADDRESS=<your_deployed_NodeRegistry_address>
SESSION_MANAGER_ADDRESS=<your_deployed_SessionManager_address>
# Add TON wallet mnemonic (24 words)
TON_WALLET_MNEMONIC=word1 word2 word3 ... word24
# WireGuard keys will be auto-generated on first runpnpm startThe daemon exposes a REST API on port 8080:
Health check and status
Response:
{
"success": true,
"status": "online",
"uptime": 123.45,
"activeSessions": 3,
"load": "30.0%",
"maxPeers": 10
}Add a peer (called by Backend when session starts)
Request:
{
"sessionId": 123,
"clientPublicKey": "base64_wg_public_key",
"clientIP": "10.8.0.2"
}Response:
{
"success": true,
"peer": {
"sessionId": 123,
"clientIP": "10.8.0.2",
"addedAt": 1234567890
},
"config": "... WireGuard config ..."
}Remove a peer (called by Backend when session ends)
Request:
{
"sessionId": 123
}Get peer statistics
Response:
{
"success": true,
"sessionId": 123,
"stats": {
"rxBytes": 1234567,
"txBytes": 7654321,
"lastSeen": 1234567890
}
}List all active peers
On first run, the daemon:
- Generates WireGuard server keypair (if not exists)
- Registers to Backend API (off-chain) → receives nodeId
- Prepares NodeRegistry.RegisterNode transaction (on-chain)
- Note: Actual transaction sending requires manual execution for now
Every 30 seconds:
- Query SessionManager.getTotalSessions()
- For each session, query SessionManager.getSession(id)
- Filter sessions where
nodeIdmatches this node - Detect new active sessions
- Auto-add peer to WireGuard (mocked)
When Backend calls /peer/add:
- Daemon adds peer to WireGuard interface (mocked)
- Generates client config
- Returns config to Backend
When Backend calls /peer/remove:
- Daemon removes peer from WireGuard (mocked)
Every 60 seconds:
- Build heartbeat payload (status, load, active peers)
- Send POST to Backend
/api/node/heartbeat- Note: This endpoint doesn't exist yet, will fail gracefully
✅ Works Now:
- Configuration loading
- Off-chain registration to Backend API
- TON blockchain queries (testnet)
- Session monitoring & detection
- HTTP API server
- Mock WireGuard peer management
- Logging & error handling
- On-chain registration (requires manual transaction)
- Actual WireGuard commands (
wg set,wg-quick) - Heartbeat endpoint (Backend not ready)
To deploy on a real VPS:
-
Install WireGuard:
sudo apt install wireguard
-
Update
wireguard.js:- Replace mock functions with real
wgcommands - Execute:
wg set wg0 peer <pubkey> allowed-ips <ip> - Parse:
wg show wg0 dumpfor stats
- Replace mock functions with real
-
Configure Public Endpoint:
- Update
NODE_ENDPOINTto public IP:port - Ensure port 51820 UDP is open
- Update
-
Add Heartbeat Endpoint to Backend:
- Implement
POST /api/node/heartbeat - Accept nodeId, status, load, activePeers
- Implement
-
Run as Systemd Service:
sudo systemctl enable devpn-node-provider sudo systemctl start devpn-node-provider
Logs are written to:
logs/combined.log- All logslogs/error.log- Errors only- Console output (colored)
pnpm startcurl http://localhost:8080/healthcurl -X POST http://localhost:8080/peer/add \
-H "Content-Type: application/json" \
-d '{
"sessionId": 1,
"clientPublicKey": "test_pubkey_123",
"clientIP": "10.8.0.2"
}'curl http://localhost:8080/peerscurl -X DELETE http://localhost:8080/peer/remove \
-H "Content-Type: application/json" \
-d '{"sessionId": 1}'BACKEND_URL- Backend API URLNODE_REGION- Region (e.g., "Asia")NODE_COUNTRY- Country (e.g., "Indonesia")SESSION_MANAGER_ADDRESS- Deployed SessionManager contractTON_NETWORK- Network (testnet/mainnet)TON_API_URL- TON API endpoint
NODE_REGISTRY_ADDRESS- NodeRegistry contract (for on-chain registration)TON_WALLET_MNEMONIC- For on-chain transactionsPRICE_PER_GB- Pricing in nanoTON (default: 100000)MAX_PEERS- Max concurrent peers (default: 10)LOG_LEVEL- debug/info/warn/error (default: debug)
Issue: "Missing required environment variables"
Fix: Check .env file has all required fields
Issue: "Failed to initialize blockchain client"
Fix: Verify SESSION_MANAGER_ADDRESS is valid and TON_API_URL is accessible
Issue: "Heartbeat disabled after 5 failed attempts"
Fix: Normal! Backend endpoint /api/node/heartbeat doesn't exist yet
Issue: "No active sessions for node" Fix: Normal if no users have started sessions yet. Test by manually calling SessionManager.StartSession on testnet
- Deploy SessionManager (if not done): Get contract address for
.env - Deploy NodeRegistry (if not done): Get contract address for
.env - Test locally: Start daemon, test API endpoints
- Get VPS: Deploy to production with real WireGuard
- Add Backend heartbeat endpoint: Enable health monitoring
- Test end-to-end: Full session flow with client
ISC