mirror of
https://github.com/bitinflow/server.git
synced 2026-04-30 10:54:01 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7d0effa90 | ||
|
|
4985175968 | ||
|
|
779ed39b4f | ||
|
|
8d78956355 | ||
|
|
7f6640a9d6 | ||
|
|
386910032e | ||
|
|
cfdb42ee9c | ||
|
|
8af4fe19b8 | ||
|
|
8d91892ace | ||
|
|
4b485fecda | ||
|
|
fa4802d488 | ||
|
|
5046c360ba | ||
|
|
57ebcc90e1 | ||
|
|
dd7d8d6aa6 |
@@ -1,9 +1,10 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
require('stackup');
|
||||||
var log = require('bookrc');
|
var log = require('bookrc');
|
||||||
var dotenv = require('dotenv').load();
|
var localenv = require('localenv');
|
||||||
var optimist = require('optimist');
|
|
||||||
var debug = require('debug')('localtunnel');
|
var debug = require('debug')('localtunnel');
|
||||||
|
var optimist = require('optimist');
|
||||||
|
|
||||||
var argv = optimist
|
var argv = optimist
|
||||||
.usage('Usage: $0 --port [num]')
|
.usage('Usage: $0 --port [num]')
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/// bookrc logging setup
|
/// bookrc logging setup
|
||||||
var log = require('book').default();
|
var log = require('book').default();
|
||||||
require('stackup');
|
|
||||||
|
|
||||||
log.use(require('book-git')(__dirname));
|
log.use(require('book-git')(__dirname));
|
||||||
log.use(require('book-raven')(process.env.SENTRY_DSN));
|
log.use(require('book-raven')(process.env.SENTRY_DSN));
|
||||||
|
|||||||
33
devops/nginx/nginx.conf
Normal file
33
devops/nginx/nginx.conf
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
user nginx;
|
||||||
|
worker_processes 1;
|
||||||
|
|
||||||
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 10240;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
access_log off;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
#tcp_nopush on;
|
||||||
|
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_min_length 1000;
|
||||||
|
|
||||||
|
include /etc/nginx/conf.d/*.conf;
|
||||||
|
include /etc/nginx/sites/*;
|
||||||
|
}
|
||||||
65
devops/nginx/sites/localtunnel
Normal file
65
devops/nginx/sites/localtunnel
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
proxy_http_version 1.1;
|
||||||
|
|
||||||
|
# http://nginx.org/en/docs/http/websocket.html
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream lt-server {
|
||||||
|
server 127.0.0.1:2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80 default_server;
|
||||||
|
listen [::]:80 default_server ipv6only=on;
|
||||||
|
|
||||||
|
server_name .localtunnel.me;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://lt-server/;
|
||||||
|
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-Proto http;
|
||||||
|
proxy_set_header X-NginX-Proxy true;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
|
||||||
|
proxy_redirect off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 default_server ssl spdy;
|
||||||
|
listen [::]:443 default_server ipv6only=on;
|
||||||
|
|
||||||
|
server_name .localtuunel.me;
|
||||||
|
|
||||||
|
ssl on;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/ssl/STAR.localtunnel.me.crt;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/STAR.localtunnel.me.key;
|
||||||
|
|
||||||
|
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
ssl_ciphers RC4:HIGH:!aNULL:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
|
||||||
|
ssl_session_cache shared:SSL:10m;
|
||||||
|
ssl_session_timeout 10m;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://lt-server/;
|
||||||
|
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-Proto https;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header X-NginX-Proxy true;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
|
||||||
|
proxy_redirect off;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
devops/run.sh
Normal file
5
devops/run.sh
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
docker run --restart always --name localtunnel -d --net host defunctzombie/localtunnel-server:0.0.5 bin/server --secure --port 2000 --max-sockets 5
|
||||||
|
|
||||||
|
docker run --restart always --name nginx -d --net host -v /home/core/nginx/nginx.conf:/etc/nginx/nginx.conf -v /home/core/nginx/sites:/etc/nginx/sites -v /home/core/nginx/ssl:/etc/nginx/ssl nginx:1.7.8
|
||||||
65
nginx.conf
65
nginx.conf
@@ -1,65 +0,0 @@
|
|||||||
proxy_http_version 1.1;
|
|
||||||
|
|
||||||
# http://nginx.org/en/docs/http/websocket.html
|
|
||||||
map $http_upgrade $connection_upgrade {
|
|
||||||
default upgrade;
|
|
||||||
'' close;
|
|
||||||
}
|
|
||||||
|
|
||||||
upstream lt-server {
|
|
||||||
server 127.0.0.1:8000;
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 80 default_server;
|
|
||||||
listen [::]:80 default_server ipv6only=on;
|
|
||||||
|
|
||||||
server_name .localtunnel.me;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://lt-server/;
|
|
||||||
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header X-Forwarded-Proto http;
|
|
||||||
proxy_set_header X-NginX-Proxy true;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection $connection_upgrade;
|
|
||||||
|
|
||||||
proxy_redirect off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 443 default_server ssl spdy;
|
|
||||||
listen [::]:443 default_server ipv6only=on;
|
|
||||||
|
|
||||||
server_name .localtuunel.me;
|
|
||||||
|
|
||||||
ssl on;
|
|
||||||
|
|
||||||
ssl_certificate ...;
|
|
||||||
ssl_certificate_key ...;
|
|
||||||
|
|
||||||
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
|
|
||||||
ssl_ciphers RC4:HIGH:!aNULL:!MD5;
|
|
||||||
ssl_prefer_server_ciphers on;
|
|
||||||
|
|
||||||
ssl_session_cache shared:SSL:10m;
|
|
||||||
ssl_session_timeout 10m;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://lt-server/;
|
|
||||||
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header X-Forwarded-Proto https;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header X-NginX-Proxy true;
|
|
||||||
proxy_set_header Connection $connection_upgrade;
|
|
||||||
|
|
||||||
proxy_redirect off;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
package.json
29
package.json
@@ -2,32 +2,33 @@
|
|||||||
"author": "Roman Shtylman <shtylman@gmail.com>",
|
"author": "Roman Shtylman <shtylman@gmail.com>",
|
||||||
"name": "localtunnel-server",
|
"name": "localtunnel-server",
|
||||||
"description": "expose localhost to the world",
|
"description": "expose localhost to the world",
|
||||||
"version": "0.0.5",
|
"version": "0.0.8",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/shtylman/localtunnel-server.git"
|
"url": "git://github.com/shtylman/localtunnel-server.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"book": "1.3.1",
|
"book": "1.3.1",
|
||||||
"optimist": "0.6.1",
|
|
||||||
"debug": "2.1.0",
|
|
||||||
"bookrc": "0.0.1",
|
|
||||||
"book-git": "0.0.2",
|
"book-git": "0.0.2",
|
||||||
"book-raven": "1.0.1",
|
"book-raven": "1.0.1",
|
||||||
"browserkthx": "0.0.2",
|
"bookrc": "0.0.1",
|
||||||
"hbs": "2.7.0",
|
|
||||||
"taters": "1.0.0",
|
|
||||||
"express": "4.10.5",
|
|
||||||
"makeup": "0.0.1",
|
|
||||||
"enchilada": "0.11.0",
|
|
||||||
"bouncy": "3.2.2",
|
"bouncy": "3.2.2",
|
||||||
|
"browserkthx": "0.0.2",
|
||||||
|
"debug": "2.1.0",
|
||||||
|
"enchilada": "0.11.0",
|
||||||
|
"express": "4.10.5",
|
||||||
|
"hbs": "2.7.0",
|
||||||
|
"localenv": "0.2.2",
|
||||||
|
"makeover": "0.0.1",
|
||||||
|
"makeup": "0.0.1",
|
||||||
|
"on-finished": "2.2.0",
|
||||||
|
"optimist": "0.6.1",
|
||||||
|
"serve-favicon": "2.1.7",
|
||||||
"stackup": "0.0.5",
|
"stackup": "0.0.5",
|
||||||
"stylish": "0.5.0",
|
"stylish": "0.5.0",
|
||||||
"makeover": "0.0.1",
|
"taters": "1.0.0",
|
||||||
"tldjs": "1.5.1",
|
"tldjs": "1.5.1",
|
||||||
"on-finished": "2.1.1",
|
"ws": "0.6.5"
|
||||||
"localenv": "0.2.2",
|
|
||||||
"serve-favicon": "2.1.7"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "2.0.1",
|
"mocha": "2.0.1",
|
||||||
|
|||||||
28
proxy.js
28
proxy.js
@@ -21,16 +21,13 @@ var Proxy = function(opt, cb) {
|
|||||||
|
|
||||||
// new tcp server to service requests for this client
|
// new tcp server to service requests for this client
|
||||||
var client_server = net.createServer();
|
var client_server = net.createServer();
|
||||||
client_server.listen(function() {
|
|
||||||
var port = client_server.address().port;
|
|
||||||
debug('tcp server listening on port: %d', port);
|
|
||||||
|
|
||||||
cb(null, {
|
client_server.on('error', function(err) {
|
||||||
// port for lt client tcp connections
|
if (err.code == 'ECONNRESET' || err.code == 'ETIMEDOUT') {
|
||||||
port: port,
|
return;
|
||||||
// maximum number of tcp connections allowed by lt client
|
}
|
||||||
max_conn_count: max_tcp_sockets
|
|
||||||
});
|
log.error(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
// track initial user connection setup
|
// track initial user connection setup
|
||||||
@@ -71,7 +68,6 @@ var Proxy = function(opt, cb) {
|
|||||||
|
|
||||||
// new tcp connection from lt client
|
// new tcp connection from lt client
|
||||||
client_server.on('connection', function(socket) {
|
client_server.on('connection', function(socket) {
|
||||||
|
|
||||||
// no more socket connections allowed
|
// no more socket connections allowed
|
||||||
if (self.sockets.length >= max_tcp_sockets) {
|
if (self.sockets.length >= max_tcp_sockets) {
|
||||||
return socket.end();
|
return socket.end();
|
||||||
@@ -119,8 +115,16 @@ var Proxy = function(opt, cb) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client_server.on('error', function(err) {
|
client_server.listen(function() {
|
||||||
log.error(err);
|
var port = client_server.address().port;
|
||||||
|
debug('tcp server listening on port: %d', port);
|
||||||
|
|
||||||
|
cb(null, {
|
||||||
|
// port for lt client tcp connections
|
||||||
|
port: port,
|
||||||
|
// maximum number of tcp connections allowed by lt client
|
||||||
|
max_conn_count: max_tcp_sockets
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ function maybe_bounce(req, res, bounce) {
|
|||||||
// we can't respond to these requests
|
// we can't respond to these requests
|
||||||
var finished = false;
|
var finished = false;
|
||||||
on_finished(res, function(err) {
|
on_finished(res, function(err) {
|
||||||
|
if (req.headers['upgrade'] == 'websocket') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
finished = true;
|
finished = true;
|
||||||
req.connection.destroy();
|
req.connection.destroy();
|
||||||
});
|
});
|
||||||
@@ -197,8 +201,8 @@ module.exports = function(opt) {
|
|||||||
var req_id = req.param('req_id');
|
var req_id = req.param('req_id');
|
||||||
|
|
||||||
// limit requested hostnames to 20 characters
|
// limit requested hostnames to 20 characters
|
||||||
if (! /^[A-Za-z0-9]{4,20}$/.test(req_id)) {
|
if (! /^[a-z0-9]{4,20}$/.test(req_id)) {
|
||||||
var err = new Error('Invalid subdomain. Subdomains must be between 4 and 20 alphanumeric characters.');
|
var err = new Error('Invalid subdomain. Subdomains must be lowercase and between 4 and 20 alphanumeric characters.');
|
||||||
err.statusCode = 403;
|
err.statusCode = 403;
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,20 @@ test('request domain that is too long', function(done) {
|
|||||||
|
|
||||||
localtunnel(test._fake_port, opt, function(err, tunnel) {
|
localtunnel(test._fake_port, opt, function(err, tunnel) {
|
||||||
assert(err);
|
assert(err);
|
||||||
assert.equal(err.message, 'Invalid subdomain. Subdomains must be between 4 and 20 alphanumeric characters.');
|
assert.equal(err.message, 'Invalid subdomain. Subdomains must be lowercase and between 4 and 20 alphanumeric characters.');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('request uppercase domain', function(done) {
|
||||||
|
var opt = {
|
||||||
|
host: 'http://localhost:' + lt_server_port,
|
||||||
|
subdomain: 'ABCD'
|
||||||
|
};
|
||||||
|
|
||||||
|
localtunnel(test._fake_port, opt, function(err, tunnel) {
|
||||||
|
assert(err);
|
||||||
|
assert.equal(err.message, 'Invalid subdomain. Subdomains must be lowercase and between 4 and 20 alphanumeric characters.');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
63
test/websocket.js
Normal file
63
test/websocket.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
var http = require('http');
|
||||||
|
var url = require('url');
|
||||||
|
var assert = require('assert');
|
||||||
|
var localtunnel = require('localtunnel');
|
||||||
|
var WebSocket = require('ws');
|
||||||
|
var WebSocketServer = require('ws').Server;
|
||||||
|
|
||||||
|
var localtunnel_server = require('../server')();
|
||||||
|
|
||||||
|
var lt_server_port
|
||||||
|
|
||||||
|
test('setup localtunnel server', function(done) {
|
||||||
|
var server = localtunnel_server.listen(function() {
|
||||||
|
lt_server_port = server.address().port;
|
||||||
|
console.log('lt server on:', lt_server_port);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('setup local websocket server', function(done) {
|
||||||
|
|
||||||
|
var wss = new WebSocketServer({ port: 0 }, function() {
|
||||||
|
test._fake_port = wss._server.address().port;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
wss.on('connection', function connection(ws) {
|
||||||
|
ws.on('message', function incoming(message) {
|
||||||
|
ws.send(message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('setup localtunnel client', function(done) {
|
||||||
|
var opt = {
|
||||||
|
host: 'http://localhost:' + lt_server_port,
|
||||||
|
};
|
||||||
|
|
||||||
|
localtunnel(test._fake_port, opt, function(err, tunnel) {
|
||||||
|
assert.ifError(err);
|
||||||
|
var url = tunnel.url;
|
||||||
|
assert.ok(new RegExp('^http:\/\/.*localhost:' + lt_server_port + '$').test(url));
|
||||||
|
test._fake_url = url;
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('test websocket server request', function(done) {
|
||||||
|
var hostname = url.parse(test._fake_url).hostname;
|
||||||
|
var ws = new WebSocket('http://localhost:' + lt_server_port, {
|
||||||
|
headers: {
|
||||||
|
host: hostname + '.tld'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ws.on('message', function(msg) {
|
||||||
|
assert.equal(msg, 'something');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('open', function open() {
|
||||||
|
ws.send('something');
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user