Publish a local server through a tunnel with PROXYSERVER() and PROXYCLIENT()
PROXY() forwards a request to a server that the proxy can reach. A tunnel is for the opposite case: the program is on a laptop or behind a firewall, so nobody can connect to it, but it can connect out. PROXYSERVER() and PROXYCLIENT() make that with one WebSocket that the private side opens:
PROXYSERVER([endpoint], [socketendpoint], [logger])runs on the public server. Every request belowendpoint(default/) is sent through the tunnel;socketendpoint(default/) is the WebSocket address where the client connects. Use different addresses when the same application serves anything else: a proxy on/takes every request, also the ones of your own routes (it runs before them).loggeris a function (default: prints with the date); passnullfor none.PROXYCLIENT(serverurl, port, [logger])runs on the private side (in this example the address of the server is built withCONF.$port, the port of the application).serverurlis the address of the WebSocket of the server (ws://orwss://;httpis changed tows) andportis3000orip:3000, the local program that receives the requests. It returns the WebSocket client.- One client at a time: when a second client connects, the server closes it with the code
4001. Without a client the answer of the server isNot yet available.. - The local program receives the whole path of the original request, including the
endpoint(/tunnel/hello), the headers of the visitor and anx-proxy: Total.jsheader, withhostset to the local address. - The WebSocket route has no authentication of its own: do not publish it without something in front of it that decides who can connect (the address is the secret, a
checkof your own, a firewall).
Here one application is both sides: a small local program on port 9511 (any program would do), the server on /tunnel/ and the client that connects to the same application.
// The program that is "private": an ordinary HTTP server that only listens on the loopback address
require('http').createServer(function(req, res) {
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({ path: req.url, via: req.headers['x-proxy'] || null, host: req.headers.host }));
}).listen(9511, '127.0.0.1');exports.install = function() {
ROUTE('GET /status/', status);
ROUTE('POST /connect/', connect);
};
// The public side: /tunnel/* goes through the tunnel, the WebSocket of the client is /tunnel-socket/. No logger.
PROXYSERVER('/tunnel/', '/tunnel-socket/', null);
let client = null;
function connect($) {
client = PROXYCLIENT('ws://127.0.0.1:' + CONF.$port + '/tunnel-socket/', '9511', null);
$.json({ connecting: true });
}
function status($) {
$.json({ connected: !!client });
}