Compare commits
	
		
			No commits in common. "bb018c538dbb3a492fbe5796e3a8d15e52294b6d" and "d700b514941a69291e86d1d644a22859ae27fc71" have entirely different histories.
		
	
	
		
			bb018c538d
			...
			d700b51494
		
	
		
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,10 +1,4 @@ | |||||||
| node_modules.* | node_modules.* | ||||||
| include |  | ||||||
| bin/node |  | ||||||
| bin/npm |  | ||||||
| bin/npx |  | ||||||
| share |  | ||||||
| etc |  | ||||||
| 
 | 
 | ||||||
| # Logs | # Logs | ||||||
| logs | logs | ||||||
|  | |||||||
							
								
								
									
										35
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								README.md
									
									
									
									
									
								
							| @ -63,41 +63,6 @@ Windows & Node.js | |||||||
| 
 | 
 | ||||||
| There is [a bug](https://github.com/nodejs/node/issues/20241) in node v9.x that causes telebit-relay to crash. | There is [a bug](https://github.com/nodejs/node/issues/20241) in node v9.x that causes telebit-relay to crash. | ||||||
| 
 | 
 | ||||||
| Manually Install |  | ||||||
| ----------- |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| git clone https://git.coolaj86.com/coolaj86/telebit-relay.js.git telebit-relay |  | ||||||
| 
 |  | ||||||
| # we're very picky to due to bugs in various versions of v8, v9, and v10 |  | ||||||
| export NODEJS_VER="v10.2.1" |  | ||||||
| 
 |  | ||||||
| # We can keep everything self-contained |  | ||||||
| export NPM_CONFIG_PREFIX=/opt/telebit-relay |  | ||||||
| export NODE_PATH=/opt/telebit-relay/lib/node_modules |  | ||||||
| 
 |  | ||||||
| curl -fsSL https://bit.ly/node-installer | bash -s -- --no-dev-deps |  | ||||||
| 
 |  | ||||||
| pushd /opt/telebit-relay |  | ||||||
|   bin/node bin/npm install |  | ||||||
|   rsync -a examples/telebit-relay.yml etc/telebit-relay.yml |  | ||||||
|   rsync -a dist/etc/systemd/system/telebit-relay.service /etc/systemd/system/telebit-relay.service |  | ||||||
| popd |  | ||||||
| 
 |  | ||||||
| # IMPORTANT: Season the config file to taste |  | ||||||
| # IMPORTANT: change your email address and domain |  | ||||||
| edit /opt/telebit-relay/etc/telebit-relay.yml |  | ||||||
| 
 |  | ||||||
| adduser --home /opt/telebit-relay --gecos '' --disabled-password telebit >/dev/null 2>&1 |  | ||||||
| sudo chown -R telebit:telebit /opt/telebit-relay/ |  | ||||||
| 
 |  | ||||||
| systemctl daemon-reload |  | ||||||
| systemctl restart telebit-relay |  | ||||||
| 
 |  | ||||||
| systemctl status telebit-relay |  | ||||||
| journalctl -xefu telebit-relay |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| Usage | Usage | ||||||
| ==== | ==== | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,7 +0,0 @@ | |||||||
| { "terms_of_service": ":hostname/tos/" |  | ||||||
| , "api_host": ":hostname" |  | ||||||
| , "tunnel": { |  | ||||||
|     "method": "wss" |  | ||||||
|   , "pathname": "" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -134,7 +134,7 @@ function applyConfig(config) { | |||||||
|     // TODO specify extensions in config file
 |     // TODO specify extensions in config file
 | ||||||
|     state.extensions = require('../lib/extensions'); |     state.extensions = require('../lib/extensions'); | ||||||
|   } catch(e) { |   } catch(e) { | ||||||
|     if ('ENOENT' !== e.code || state.debug) { console.log('[DEBUG] no extensions loaded', e); } |     if (state.debug) { console.log('[DEBUG] no extensions loaded', e); } | ||||||
|     state.extensions = {}; |     state.extensions = {}; | ||||||
|   } |   } | ||||||
|   require('../lib/handlers').create(state); // adds directly to config for now...
 |   require('../lib/handlers').create(state); // adds directly to config for now...
 | ||||||
|  | |||||||
| @ -2,8 +2,6 @@ email: 'jon@example.com'       # must be valid (for certificate recovery and sec | |||||||
| agree_tos: true                # agree to the Telebit, Greenlock, and Let's Encrypt TOSes | agree_tos: true                # agree to the Telebit, Greenlock, and Let's Encrypt TOSes | ||||||
| community_member: true         # receive infrequent relevant updates | community_member: true         # receive infrequent relevant updates | ||||||
| telemetry: true                # contribute to project telemetric data | telemetry: true                # contribute to project telemetric data | ||||||
| webmin_domain: example.com |  | ||||||
| shared_domain: xm.pl |  | ||||||
| servernames:                   # hostnames that direct to the Telebit Relay admin console | servernames:                   # hostnames that direct to the Telebit Relay admin console | ||||||
|   - telebit.example.com |   - telebit.example.com | ||||||
|   - telebit.example.net |   - telebit.example.net | ||||||
| @ -68,7 +68,6 @@ my_app="telebit-relay" | |||||||
| my_bin="telebit-relay.js" | my_bin="telebit-relay.js" | ||||||
| my_name="Telebit Relay" | my_name="Telebit Relay" | ||||||
| my_repo="telebit-relay.js" | my_repo="telebit-relay.js" | ||||||
| exec 3<>/dev/tty |  | ||||||
| 
 | 
 | ||||||
| if [ -z "${my_email}" ]; then | if [ -z "${my_email}" ]; then | ||||||
|   echo "" |   echo "" | ||||||
| @ -78,7 +77,7 @@ if [ -z "${my_email}" ]; then | |||||||
|   echo "To accept the Terms of Service for Telebit, Greenlock and Let's Encrypt," |   echo "To accept the Terms of Service for Telebit, Greenlock and Let's Encrypt," | ||||||
|   echo "please enter your email." |   echo "please enter your email." | ||||||
|   echo "" |   echo "" | ||||||
|   read -u 3 -p "email: " my_email |   read -p "email: " my_email | ||||||
|   echo "" |   echo "" | ||||||
|   # UX - just want a smooth transition |   # UX - just want a smooth transition | ||||||
|   sleep 0.5 |   sleep 0.5 | ||||||
| @ -87,7 +86,7 @@ fi | |||||||
| if [ -z "${my_servername}" ]; then | if [ -z "${my_servername}" ]; then | ||||||
|   echo "What is the domain of this server (for admin interface)?" |   echo "What is the domain of this server (for admin interface)?" | ||||||
|   echo "" |   echo "" | ||||||
|   read -u 3 -p "domain (ex: telebit-relay.example.com): " my_servername |   read -p "domain (ex: telebit-relay.example.com): " my_servername | ||||||
|   echo "" |   echo "" | ||||||
|   # UX - just want a smooth transition |   # UX - just want a smooth transition | ||||||
|   sleep 0.5 |   sleep 0.5 | ||||||
| @ -121,8 +120,8 @@ mkdir -p $my_tmp | |||||||
| 
 | 
 | ||||||
| echo "sudo mkdir -p '$TELEBIT_RELAY_PATH'" | echo "sudo mkdir -p '$TELEBIT_RELAY_PATH'" | ||||||
| sudo mkdir -p "$TELEBIT_RELAY_PATH" | sudo mkdir -p "$TELEBIT_RELAY_PATH" | ||||||
| echo "sudo mkdir -p '$TELEBIT_RELAY_PATH/etc'" | echo "sudo mkdir -p '/opt/$my_app/etc'" | ||||||
| sudo mkdir -p "$TELEBIT_RELAY_PATH/etc/" | sudo mkdir -p "/opt/$my_app/etc/" | ||||||
| 
 | 
 | ||||||
| set +e | set +e | ||||||
| #https://git.coolaj86.com/coolaj86/telebit-relay.js.git | #https://git.coolaj86.com/coolaj86/telebit-relay.js.git | ||||||
| @ -173,17 +172,17 @@ if [ -z "$(cat /etc/passwd | grep $my_user)" ]; then | |||||||
|   sudo adduser --home $TELEBIT_RELAY_PATH --gecos '' --disabled-password $my_user >/dev/null 2>&1 |   sudo adduser --home $TELEBIT_RELAY_PATH --gecos '' --disabled-password $my_user >/dev/null 2>&1 | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| if [ ! -f "$TELEBIT_RELAY_PATH/etc/$my_app.yml" ]; then | if [ ! -f "/opt/$my_app/etc/$my_app.yml" ]; then | ||||||
|   echo "### Creating config file from template. sudo may be required" |   echo "### Creating config file from template. sudo may be required" | ||||||
|   #echo "sudo rsync -a examples/$my_app.yml $TELEBIT_RELAY_PATH/etc/$my_app.yml" |   #echo "sudo rsync -a examples/$my_app.yml /opt/$my_app/etc/$my_app.yml" | ||||||
|   sudo bash -c "echo 'email: $my_email' >> $TELEBIT_RELAY_PATH/etc/$my_app.yml" |   sudo bash -c "echo 'email: $my_email' >> /opt/$my_app/etc/$my_app.yml" | ||||||
|   sudo bash -c "echo 'secret: $my_secret' >> $TELEBIT_RELAY_PATH/etc/$my_app.yml" |   sudo bash -c "echo 'secret: $my_secret' >> /opt/$my_app/etc/$my_app.yml" | ||||||
|   sudo bash -c "echo 'servernames: [ $my_servername ]' >> $TELEBIT_RELAY_PATH/etc/$my_app.yml" |   sudo bash -c "echo 'servernames: [ $my_servername ]' >> /opt/$my_app/etc/$my_app.yml" | ||||||
|   sudo bash -c "cat $TELEBIT_RELAY_PATH/examples/$my_app.yml.tpl >> $TELEBIT_RELAY_PATH/etc/$my_app.yml" |   sudo bash -c "cat examples/$my_app.yml.tpl >> /opt/$my_app/etc/$my_app.yml" | ||||||
| fi | fi | ||||||
| 
 | 
 | ||||||
| echo "sudo chown -R $my_user '$TELEBIT_RELAY_PATH'" | echo "sudo chown -R $my_user '$TELEBIT_RELAY_PATH' '/opt/$my_app/etc'" | ||||||
| sudo chown -R $my_user "$TELEBIT_RELAY_PATH" | sudo chown -R $my_user "$TELEBIT_RELAY_PATH" "/opt/$my_app/etc" | ||||||
| 
 | 
 | ||||||
| echo "### Adding $my_app is a system service" | echo "### Adding $my_app is a system service" | ||||||
| echo "sudo rsync -a $TELEBIT_RELAY_PATH/dist/etc/systemd/system/$my_app.service /etc/systemd/system/$my_app.service" | echo "sudo rsync -a $TELEBIT_RELAY_PATH/dist/etc/systemd/system/$my_app.service /etc/systemd/system/$my_app.service" | ||||||
| @ -202,7 +201,7 @@ echo "==============================================" | |||||||
| echo "  Privacy Settings in Config" | echo "  Privacy Settings in Config" | ||||||
| echo "==============================================" | echo "==============================================" | ||||||
| echo "" | echo "" | ||||||
| echo "The example config file $TELEBIT_RELAY_PATH/etc/$my_app.yml opts-in to" | echo "The example config file /opt/$my_app/etc/$my_app.yml opts-in to" | ||||||
| echo "contributing telemetrics and receiving infrequent relevant updates" | echo "contributing telemetrics and receiving infrequent relevant updates" | ||||||
| echo "(probably once per quarter or less) such as important notes on" | echo "(probably once per quarter or less) such as important notes on" | ||||||
| echo "a new release, an important API change, etc. No spam." | echo "a new release, an important API change, etc. No spam." | ||||||
| @ -219,13 +218,13 @@ echo "==============================================" | |||||||
| echo "" | echo "" | ||||||
| echo "Edit the config and restart, if desired:" | echo "Edit the config and restart, if desired:" | ||||||
| echo "" | echo "" | ||||||
| echo "    sudo vim $TELEBIT_RELAY_PATH/etc/$my_app.yml" | echo "    sudo vim /opt/$my_app/etc/$my_app.yml" | ||||||
| echo "    sudo systemctl restart $my_app" | echo "    sudo systemctl restart $my_app" | ||||||
| echo "" | echo "" | ||||||
| echo "Or disabled the service and start manually:" | echo "Or disabled the service and start manually:" | ||||||
| echo "" | echo "" | ||||||
| echo "    sudo systemctl stop $my_app" | echo "    sudo systemctl stop $my_app" | ||||||
| echo "    sudo systemctl disable $my_app" | echo "    sudo systemctl disable $my_app" | ||||||
| echo "    $my_app --config $TELEBIT_RELAY_PATH/etc/$my_app.yml" | echo "    $my_app --config /opt/$my_app/etc/$my_app.yml" | ||||||
| echo "" | echo "" | ||||||
| sleep 1 | sleep 1 | ||||||
|  | |||||||
| @ -52,7 +52,7 @@ module.exports.create = function (state) { | |||||||
|     || redirectHttpsAndClose |     || redirectHttpsAndClose | ||||||
|   ); |   ); | ||||||
|   state.handleInsecureHttp = function (servername, socket) { |   state.handleInsecureHttp = function (servername, socket) { | ||||||
|     console.log("[handlers] insecure http for '" + servername + "'"); |     console.log("handleInsecureHttp('" + servername + "', socket)"); | ||||||
|     socket.__my_servername = servername; |     socket.__my_servername = servername; | ||||||
|     state.httpInsecureServer.emit('connection', socket); |     state.httpInsecureServer.emit('connection', socket); | ||||||
|   }; |   }; | ||||||
|  | |||||||
| @ -2,55 +2,42 @@ | |||||||
| 
 | 
 | ||||||
| var Packer = require('proxy-packer'); | var Packer = require('proxy-packer'); | ||||||
| 
 | 
 | ||||||
| module.exports = function pipeWs(servername, service, srv, conn, serviceport) { | module.exports = function pipeWs(servername, service, conn, remote, serviceport) { | ||||||
|   var browserAddr = Packer.socketToAddr(conn); |   var browserAddr = Packer.socketToAddr(conn); | ||||||
|   var cid = Packer.addrToId(browserAddr); |   var cid = Packer.addrToId(browserAddr); | ||||||
|   browserAddr.service = service; |   browserAddr.service = service; | ||||||
|   browserAddr.serviceport = serviceport; |   browserAddr.serviceport = serviceport; | ||||||
|   browserAddr.name = servername; |   browserAddr.name = servername; | ||||||
|   conn.tunnelCid = cid; |   conn.tunnelCid = cid; | ||||||
|   var rid = Packer.socketToId(srv.upgradeReq.socket); |   var rid = Packer.socketToId(remote.upgradeReq.socket); | ||||||
| 
 | 
 | ||||||
|   //if (state.debug) { console.log('[pipeWs] client', cid, '=> remote', rid, 'for', servername, 'via', service); }
 |   //if (state.debug) { console.log('[pipeWs] client', cid, '=> remote', rid, 'for', servername, 'via', service); }
 | ||||||
| 
 | 
 | ||||||
|   function sendWs(data, serviceOverride) { |   function sendWs(data, serviceOverride) { | ||||||
|     if (srv.ws && (!conn.tunnelClosing || serviceOverride)) { |     if (remote.ws && (!conn.tunnelClosing || serviceOverride)) { | ||||||
|       try { |       try { | ||||||
|         if (data && !Buffer.isBuffer(data)) { |         remote.ws.send(Packer.pack(browserAddr, data, serviceOverride), { binary: true }); | ||||||
|           data = Buffer.from(JSON.stringify(data)); |  | ||||||
|         } |  | ||||||
|         srv.ws.send(Packer.packHeader(browserAddr, data, serviceOverride), { binary: true }); |  | ||||||
|         if (data) { |  | ||||||
|           srv.ws.send(data, { binary: true }); |  | ||||||
|         } |  | ||||||
|         // If we can't send data over the websocket as fast as this connection can send it to us
 |         // If we can't send data over the websocket as fast as this connection can send it to us
 | ||||||
|         // (or there are a lot of connections trying to send over the same websocket) then we
 |         // (or there are a lot of connections trying to send over the same websocket) then we
 | ||||||
|         // need to pause the connection for a little. We pause all connections if any are paused
 |         // need to pause the connection for a little. We pause all connections if any are paused
 | ||||||
|         // to make things more fair so a connection doesn't get stuck waiting for everyone else
 |         // to make things more fair so a connection doesn't get stuck waiting for everyone else
 | ||||||
|         // to finish because it got caught on the boundary. Also if serviceOverride is set it
 |         // to finish because it got caught on the boundary. Also if serviceOverride is set it
 | ||||||
|         // means the connection is over, so no need to pause it.
 |         // means the connection is over, so no need to pause it.
 | ||||||
|         if (!serviceOverride && (srv.pausedConns.length || srv.ws.bufferedAmount > 1024*1024)) { |         if (!serviceOverride && (remote.pausedConns.length || remote.ws.bufferedAmount > 1024*1024)) { | ||||||
|           // console.log('pausing', cid, 'to allow web socket to catch up');
 |           // console.log('pausing', cid, 'to allow web socket to catch up');
 | ||||||
|           conn.pause(); |           conn.pause(); | ||||||
|           srv.pausedConns.push(conn); |           remote.pausedConns.push(conn); | ||||||
|         } |         } | ||||||
|       } catch (err) { |       } catch (err) { | ||||||
|         console.warn('[pipeWs] srv', rid, ' => client', cid, 'error sending websocket message', err); |         console.warn('[pipeWs] remote', rid, ' => client', cid, 'error sending websocket message', err); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   srv.clients[cid] = conn; |   remote.clients[cid] = conn; | ||||||
|   conn.servername = servername; |  | ||||||
|   conn.serviceport = serviceport; |  | ||||||
|   conn.service = service; |  | ||||||
| 
 | 
 | ||||||
|   // send peek at data too?
 |  | ||||||
|   srv.ws.send(Packer.packHeader(browserAddr, null, 'connection'), { binary: true }); |  | ||||||
| 
 |  | ||||||
|   // TODO convert to read stream?
 |  | ||||||
|   conn.on('data', function (chunk) { |   conn.on('data', function (chunk) { | ||||||
|     //if (state.debug) { console.log('[pipeWs] client', cid, ' => srv', rid, chunk.byteLength, 'bytes'); }
 |     //if (state.debug) { console.log('[pipeWs] client', cid, ' => remote', rid, chunk.byteLength, 'bytes'); }
 | ||||||
|     sendWs(chunk); |     sendWs(chunk); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
| @ -61,7 +48,7 @@ module.exports = function pipeWs(servername, service, srv, conn, serviceport) { | |||||||
|   conn.on('close', function (hadErr) { |   conn.on('close', function (hadErr) { | ||||||
|     //if (state.debug) { console.log('[pipeWs] client', cid, 'closing'); }
 |     //if (state.debug) { console.log('[pipeWs] client', cid, 'closing'); }
 | ||||||
|     sendWs(null, hadErr ? 'error': 'end'); |     sendWs(null, hadErr ? 'error': 'end'); | ||||||
|     delete srv.clients[cid]; |     delete remote.clients[cid]; | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										951
									
								
								lib/relay.js
									
									
									
									
									
								
							
							
						
						
									
										951
									
								
								lib/relay.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -19,11 +19,6 @@ module.exports.createTcpConnectionHandler = function (state) { | |||||||
| 
 | 
 | ||||||
|     //return;
 |     //return;
 | ||||||
|     conn.once('data', function (firstChunk) { |     conn.once('data', function (firstChunk) { | ||||||
|       var service = 'tcp'; |  | ||||||
|       var servername; |  | ||||||
|       var str; |  | ||||||
|       var m; |  | ||||||
| 
 |  | ||||||
|       conn.pause(); |       conn.pause(); | ||||||
|       conn.unshift(firstChunk); |       conn.unshift(firstChunk); | ||||||
| 
 | 
 | ||||||
| @ -36,13 +31,18 @@ module.exports.createTcpConnectionHandler = function (state) { | |||||||
|       // defer after return (instead of being in many places)
 |       // defer after return (instead of being in many places)
 | ||||||
|       function deferData(fn) { |       function deferData(fn) { | ||||||
|         if (fn) { |         if (fn) { | ||||||
|           state[fn](servername, conn); |           state[fn](servername, conn) | ||||||
|         } |         } | ||||||
|         process.nextTick(function () { |         process.nextTick(function () { | ||||||
|           conn.resume(); |           conn.resume(); | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  |       var service = 'tcp'; | ||||||
|  |       var servername; | ||||||
|  |       var str; | ||||||
|  |       var m; | ||||||
|  | 
 | ||||||
|       function tryTls() { |       function tryTls() { | ||||||
|         var vhost; |         var vhost; | ||||||
| 
 | 
 | ||||||
| @ -76,9 +76,9 @@ module.exports.createTcpConnectionHandler = function (state) { | |||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           if (state.debug) { console.log("pipeWs(servername, service, deviceLists['" + servername + "'], socket)"); } |           if (state.debug) { console.log("pipeWs(servername, service, socket, deviceLists['" + servername + "'])"); } | ||||||
|           deferData(); |           deferData(); | ||||||
|           pipeWs(servername, service, nextDevice, conn, serviceport); |           pipeWs(servername, service, conn, nextDevice, serviceport); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // TODO don't run an fs check if we already know this is working elsewhere
 |         // TODO don't run an fs check if we already know this is working elsewhere
 | ||||||
| @ -90,7 +90,7 @@ module.exports.createTcpConnectionHandler = function (state) { | |||||||
|           //return;
 |           //return;
 | ||||||
|           require('fs').readdir(vhost, function (err, nodes) { |           require('fs').readdir(vhost, function (err, nodes) { | ||||||
|             if (state.debug && err) { console.log("VHOST error", err); } |             if (state.debug && err) { console.log("VHOST error", err); } | ||||||
|             if (err || !nodes) { run(); return; } |             if (err) { run(); return; }  | ||||||
|             //if (nodes) { deferData('httpsVhost'); return; }
 |             //if (nodes) { deferData('httpsVhost'); return; }
 | ||||||
|             deferData('httpsVhost'); |             deferData('httpsVhost'); | ||||||
|           }); |           }); | ||||||
| @ -131,7 +131,7 @@ module.exports.createTcpConnectionHandler = function (state) { | |||||||
|             // HTTP
 |             // HTTP
 | ||||||
|             if (Devices.exist(state.deviceLists, servername)) { |             if (Devices.exist(state.deviceLists, servername)) { | ||||||
|               deferData(); |               deferData(); | ||||||
|               pipeWs(servername, service, Devices.next(state.deviceLists, servername), conn, serviceport); |               pipeWs(servername, service, conn, Devices.next(state.deviceLists, servername), serviceport); | ||||||
|               return; |               return; | ||||||
|             } |             } | ||||||
|             deferData('handleHttp'); |             deferData('handleHttp'); | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "telebit-relay", |   "name": "telebit-relay", | ||||||
|   "version": "0.20.0", |   "version": "0.12.1", | ||||||
|   "description": "Friends don't let friends localhost. Expose your bits with a secure connection even from behind NAT, Firewalls, in a box, with a fox, on a train or in a plane... or a Raspberry Pi in your closet. An attempt to create a better localtunnel.me server, a more open ngrok. Uses Automated HTTPS (Free SSL) via ServerName Indication (SNI). Can also tunnel tls and plain tcp.", |   "description": "Friends don't let friends localhost. Expose your bits with a secure connection even from behind NAT, Firewalls, in a box, with a fox, on a train or in a plane... or a Raspberry Pi in your closet. An attempt to create a better localtunnel.me server, a more open ngrok. Uses Automated HTTPS (Free SSL) via ServerName Indication (SNI). Can also tunnel tls and plain tcp.", | ||||||
|   "main": "lib/relay.js", |   "main": "lib/relay.js", | ||||||
|   "bin": { |   "bin": { | ||||||
| @ -43,8 +43,8 @@ | |||||||
|     "greenlock": "^2.2.4", |     "greenlock": "^2.2.4", | ||||||
|     "human-readable-ids": "^1.0.4", |     "human-readable-ids": "^1.0.4", | ||||||
|     "js-yaml": "^3.11.0", |     "js-yaml": "^3.11.0", | ||||||
|     "jsonwebtoken": "^8.3.0", |     "jsonwebtoken": "^8.2.1", | ||||||
|     "proxy-packer": "^2.0.0", |     "proxy-packer": "^1.4.3", | ||||||
|     "recase": "^1.0.4", |     "recase": "^1.0.4", | ||||||
|     "redirect-https": "^1.1.5", |     "redirect-https": "^1.1.5", | ||||||
|     "serve-static": "^1.13.2", |     "serve-static": "^1.13.2", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user