An efficient, secure localtunnel clone
An efficient, secure localtunnel clone.
localtunnel is super awesome, but it goes down frequently or kicks clients at odd intervals. Also, although it secures connections between the server and the outside world, the actual tunnels themselves are unprotected.
The localtunnel client opens ten connections to the server on startup and hopes that this number will be suitable for the majority of situations. Generally this works well enough, but if more than ten connections are required, some external consumers may starve; conversely if there is only a single consumer, the other nine connections go to waste. So, instead of trying to guess the perfect number of connections to open, this module sets up a dedicated "control" connection and uses it to ask for additional connections on demand.
$ npm install -g underpass
There should be a server up and running at tunnels.simple-machines.io, you can try it out like so:
$ up -h tunnels.simple-machines.io -n demo
This should proxy TLS connections to demo.tunnels.simple-machines.io through to your local machine. Note that if you use a custom name for your tunnel it may take a moment for your initial connection to go through while a certificate is provisioned for you.
$ up [OPTION]
$ up serve [OPTION]
[option]
-n --name ENV:NAME (random)
-p --port ENV:PORT (8080)
-h --tunnel-host ENV:TUNNEL_HOST (localhost)
-t --tunnel-port ENV:TUNNEL_PORT (9000)
-c --control-port ENV:CONTROL_PORT (9001)
-e --external-port ENV:EXTERNAL_PORT (9002)
-s --secure ENV:SECURE (true)
false
Plain TCP on both sides of the servertrue
Connections on both sides of the server are secured with TLSinternal
TLS between the server and client onlyexternal
TLS between the server and the outside world only-k --key-path ENV:KEY[_PATH]
-C --certificate-path ENV:CERT[_PATH]
-a --ca-certificate-path ENV:CA_CERT[_PATH]
var createClient = require('underpass/src/client')
var createServer = require('underpass/src/server')
var internalDevServer = http.createServer((req, res) => {
req.on('data', d => res.end(d.toString().toUpperCase()))
}).listen('8080')
var server = createServer({
tunnelPort: '9000',
controlPort: '9001',
externalPort: '9002',
// secure: true,
// SNICallback: (hostname, cb) => {
// cb(null, new tls.createSecureContext({ /* cert, key */ }))
// }
})
var client = createClient({
tunnelHost: 'localhost',
tunnelPort: '9000',
controlPort: '9001',
name: 'upper-caser',
port: '8080',
// secure: true
})
client.on('ready', () => {
http.request({
hostname: 'localhost',
port: '9002',
method: 'POST',
headers: {
host: 'upper-caser.localhost'
}
}, res => {
res.on('data', d => {
console.log(d.toString()) // => HI
client.destroy()
server.close()
})
}).end('hi')
})
npm run test
Public domain