9.7 KiB
Effective Multi Worker Connections For Web Traffic.
Multi-Worker Server and Hyper Relay: A Deep Dive into Instant URL Routing
This architecture showcases an advanced, decentralized system that combines multi-worker HTTP servers with a HyperDHT-based network to create instant, peer-to-peer URLs. Using a reverse proxy setup with wildcard DNS, the system allows users to access peers through dynamic URLs, scaling effectively with system resources.
Source Code
WebRelay
https://git.ssh.surf/hypermc/hyperMC-Web-Relay
Service Port Relay
https://git.ssh.surf/hypermc/hyper-relay
Multi-Worker Server Architecture
The multi-worker server is built using Node.js’s cluster
module to utilize all available CPU cores. By spawning worker processes, the system handles concurrent requests across the available cores, maximizing performance.
The master process first detects how many CPU cores are available:
const numCPUs = require('os').cpus().length;
For each core, the master forks a worker process:
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
}
Each worker runs its own instance of the HTTP server, ensuring that no single process becomes a bottleneck. This structure is ideal for environments handling a high volume of requests. Workers are independent and can be replaced if they crash, ensuring resilience.
When a worker dies, the master process logs the event:
cluster.on('exit', (worker) => {
console.log(`Worker ${worker.process.pid} died`);
});
The server is highly fault-tolerant, ensuring that a worker crash doesn’t disrupt the entire system.
Handling HTTP Requests with HyperDHT and Tunnels
Each worker is responsible for handling incoming HTTP and WebSocket requests. The system uses a reverse proxy, built with http-proxy
, to forward requests to peers on the HyperDHT network.
When a request arrives, the server extracts the subdomain from the host
header:
const split = req.headers.host.split('.');
This subdomain corresponds to the peer’s public key, which is encoded in Base32. The public key uniquely identifies the peer on the DHT network.
const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase()));
If the public key is valid, the system checks if a tunnel already exists for that peer:
if (!tunnels[publicKey]) {
const port = await getAvailablePort();
const server = net.createServer(function (servsock) {
const socket = dhtServer.connect(publicKey);
// Data piping logic
});
server.listen(port, "127.0.0.1", () => {
tunnels[publicKey] = port;
proxy.web(req, res, { target: 'http://127.0.0.1:' + port });
});
}
The server dynamically creates a new tunnel if one does not exist and assigns a random available port for the connection. The tunnel is created by connecting to the peer via HyperDHT, allowing data to be forwarded between the client and the peer.
WebSocket Proxying
The system also supports WebSocket connections, enabling real-time communication between clients and peers. WebSocket upgrade requests are handled similarly to HTTP requests, using the same reverse proxy mechanism.
server.on('upgrade', function (req, socket, head) {
const split = req.headers.host.split('.');
const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase()));
proxy.ws(req, socket, { target: 'http://127.0.0.1:' + tunnels[publicKey] });
});
This ensures that both HTTP and WebSocket traffic can be seamlessly routed to the appropriate peer.
HyperDHT: Decentralized Peer-to-Peer Communication
HyperDHT is the backbone of this architecture. It is a distributed hash table (DHT) that allows peers to communicate directly without relying on centralized servers. Each peer is identified by a public key, which acts as its unique identifier on the DHT network.
The DHT is based on the Kademlia algorithm, which is designed to locate peers efficiently. When a request arrives, the server uses the public key from the subdomain to find the corresponding peer on the DHT.
const socket = dhtServer.connect(publicKey);
Once connected, data can be forwarded between the client and the peer using TCP sockets. The server handles data transmission using Node.js’s stream API, allowing for bi-directional communication between the client and the peer.
Instant URLs via Public Key Subdomains
One of the standout features of this architecture is its ability to generate instant URLs. These URLs are dynamically generated based on the peer’s public key. The public key is encoded in Base32 and used as the subdomain in the URL.
For example, a peer’s public key could generate the following URL:
https://w7zpwusw6ljrgbffxtklak23rkhaxwhs2kskozteme6ofefevlia.your-tld.here/
When a client sends a request to this URL, the system extracts the public key from the subdomain, finds the peer on the DHT, and forwards the request to the peer.
This system allows for decentralized, dynamic URLs that can be generated on the fly. There is no need to pre-configure DNS records for each peer, making it highly flexible and scalable for peer-to-peer applications.
Reverse Proxy with Wildcard DNS and Apache HTTPD
To route requests to the appropriate workers, the system uses Apache HTTPD as a reverse proxy. The proxy is configured to forward all incoming requests to the worker processes running on port 8081
.
<VirtualHost *:443>
SSLProxyEngine On
ServerAlias *.your-tld.here
ProxyPass "/" "http://localhost:8081/"
ProxyPassReverse "/" "http://localhost:8081/"
</VirtualHost>
The ServerAlias
directive allows any subdomain under your-tld.here
to be routed to the same server, using a wildcard DNS entry. This is crucial for enabling dynamic subdomain-based routing.
*.your-tld.here. IN A 192.0.2.1
With this wildcard DNS setup, any subdomain request, representing a peer, can be handled by the server without needing individual DNS records for each peer.
Fault Tolerance and Scalability
The architecture is designed with both fault tolerance and scalability in mind. Each worker is independent, meaning that if one worker crashes, the others continue to handle requests. The master process can detect when a worker dies and log the event for further action.
In addition to fault tolerance, the use of multiple workers allows the system to scale horizontally. By forking worker processes based on the number of available CPU cores, the system can handle more requests simultaneously without performance degradation.
Hyper Relay Server
The relay server component plays a critical role in connecting peers through the DHT. The relay server listens on a specific port and relays connection hashes, allowing peers to find each other and establish connections.
const node = require('./relay.js')();
node.serve(key, "localhost", port);
When a peer wants to connect to another peer, it uses the relay server to broadcast its connection hash. Other peers can use this hash to initiate a connection over the HyperDHT network.
This mechanism ensures that peers can communicate even if they are behind NATs or firewalls, making the system robust for a wide range of network conditions.
Security and Encryption
HyperDHT and the entire peer-to-peer network rely heavily on cryptographic principles. Each peer’s public key is generated using a secure cryptographic algorithm, ensuring that peers can communicate securely.
Since the subdomain represents the peer’s public key, it provides a unique, tamper-proof identifier for the peer. This prevents malicious users from spoofing identities or hijacking connections.
The reverse proxy setup also supports SSL/TLS encryption via Apache HTTPD. This ensures that all traffic between the client and the server is encrypted, providing an additional layer of security.
SSLCertificateFile /path/to/fullchain.pem
SSLCertificateKeyFile /path/to/privkey.pem
By combining cryptographic public key infrastructure with SSL/TLS, the system ensures secure communication across all layers.
Dynamic Port Assignment
One of the challenges of handling multiple peers is managing the available network ports. The system dynamically assigns ports for each new peer connection, ensuring that there are no conflicts.
async function getAvailablePort() {
let port;
do {
port = 1337 + Math.floor(Math.random() * 1000);
} while (Object.values(tunnels).includes(port));
return port;
}
This function generates a random port between 1337
and 2336
for each new tunnel. It checks to ensure that the port is not already in use before assigning it to a peer.
This dynamic port allocation system allows the server to handle multiple peers concurrently without port conflicts.
Final Thoughts
The multi-worker server and hyper-relay architecture is an incredibly powerful and scalable solution for decentralized applications. By leveraging HyperDHT, dynamic URL generation, and reverse proxying, the system enables instant, peer-to-peer communication through subdomain-based routing.
This architecture is ideal for scenarios where dynamic peer connections and decentralized routing are required. The combination of Node.js’s cluster module, HyperDHT, and reverse proxying makes it a highly resilient and scalable system capable of handling large volumes of traffic in a decentralized, peer-to-peer environment.
The ability to create instant URLs for peers, combined with the security of public key cryptography and SSL/TLS encryption, makes this architecture a game-changer for modern web applications that prioritize decentralization, scalability, and security.