localtunnel / server

server for localtunnel.me
https://localtunnel.me
MIT License
3.05k stars 991 forks source link

Tunnel is disconnected almost immediately #169

Open rsurgiewicz opened 3 years ago

rsurgiewicz commented 3 years ago

Hi Folks,

First, let me start with big kudos for the solution!

I'd like to make it as self-hosting solution, but unfortunately even though I followed the readme I was not able to succeed.

The problem I've encountered is that server is running and accepting incoming connections but dropping them almost immediately.

On server side I have a linux box with ubuntu server. I've tried both dockerized version and "standard" one. My run command is node -r esm ./bin/server --port 3000 --domain tun.sub.domain.com --secure true // exact name has been changed to tun.sub.domain.com //

Added some log.debug's and on the server side I got:

localtun_1  | [debug]   server listening on port: 3000
localtun_1  | [debug]   undefined
localtun_1  | [debug]   tcp server listening on port: 42405
localtun_1  | [debug]   removing client: mighty-skunk-48
localtun_1  | [debug]   closed tcp socket
localtun_1  | [debug]   closed tcp socket
localtun_1  | [debug]   server listening on port: 3000
localtun_1  | [debug]   undefined
localtun_1  | [debug]   tcp server listening on port: 46035
localtun_1  | [debug]   removing client: helpless-cougar-46
localtun_1  | [debug]   closed tcp socket
localtun_1  | [debug]   closed tcp socket

While on the client side // I have it behind nginx listening with SSL on port 3333 (config from your repo localtunnel-nginx) that's why you see port 3333 on client side

 ✘  npx localtunnel --port 8000 --host https://tun.sub.domain.com:3333                         
your url is: https://mighty-skunk-48.tun.sub.domain.com:3333

but no traffic and /api/status reply with {tunnels:0...}

 ✘  npx localtunnel --port 8000 --host https://tun.sub.domain.com:3333                         
your url is: https://helpless-cougar-46.tun.sub.domain.com:3333

but no traffic and /api/status reply with {tunnels:0...}

Actually I've discovered that if I hit /api/status fast enough I got reply with {tunnels:1...} for a friction of a second.

Any ideas what's wrong here? Thanks a lot!

rohanpooniwala commented 3 years ago

I had a similar issue. Turns out I had to open all the ports for my server in the network firewall as Client tries to connect to assigned port on the go.

I hope this helps!

beebeebeeebeee commented 2 years ago

I had a similar issue. Turns out I had to open all the ports for my server in the network firewall as Client tries to connect to assigned port on the go.

I hope this helps!

I have stuck on that issue whole day! It works, thanks a lot! 😄

pamdla commented 2 years ago

I had a similar issue. Turns out I had to open all the ports for my server in the network firewall as Client tries to connect to assigned port on the go.

I hope this helps!

may you instruct how to to that?

smashah commented 2 years ago

@rsurgiewicz I'm also experiencing this odd behaviour.

But when I use the IP address of the VPS on the lt command it works fine:

  1. Replicating the issue (my lt server is running on port 80):
> lt --host https://my.tunnel.cloud --port 3000 -s dumberror
  1. However this works perfectly fine:
    > lt --host 123.123.123.123 --port 3000 -s dumberror

Same server. Same instance of the localtunnel server. Both return https://dumberror.my.tunnel.cloud but only the second instance survives long enough to receive the request.

I am inclined to think this is some sort of bug with the client actually.

If you see how lt client works. It tries to connect to the IP and port specified by the lt server. The server responds as expected.

I logged the return of _getInfo in the client repo. In the first non-working case this is the info:

 {
  name: 'dumberror',
  url: 'http://dumberror.my.tunnel.cloud',
  cached_url: undefined,
  max_conn: 10,
  remote_host: 'my.tunnel.cloud',
  remote_ip: undefined,
  remote_port: 46199,
  local_port: 3000,
  local_host: undefined,
  local_https: undefined,
  local_cert: undefined,
  local_key: undefined,
  local_ca: undefined,
  allow_invalid_cert: undefined
}

The second case where it does work:

 {
  name: 'dumberror',
  url: 'http://dumberror.my.tunnel.cloud',
  cached_url: undefined,
  max_conn: 10,
  remote_host: '123.123.123.123',
  remote_ip: undefined,
  remote_port: 46771,
  local_port: 3000,
  local_host: undefined,
  local_https: undefined,
  local_cert: undefined,
  local_key: undefined,
  local_ca: undefined,
  allow_invalid_cert: undefined
}

Ok so when I give the host IP explicitly it works but not with the domain. This must mean that there's an issue with my DNS setup.

I set up my domain on cloudflare. DNS is an A record. I want HTTPS built in. So I use the cloudlfare DNS with the proxy setting on.

This results in a dig my.tunnel.cloud returning some other IP address.

This is what breaks the connection between the client and the server

The client requests a connection on the server. It responds with the port that it should connect to. However, because the host is the my.tunnel.cloud and CF is proxying it - the client does not have access to that port on CF's proxy servers.

So what is the solution? Turn off proxy on CF? No because I want https automatically. Is it to hardcode the IP on my lt client request? No that's ugly.

I think the compromise is for the lt server to add it's own IP address in the tunnel creation request response json and for the info field to infer the IP of the lt server from that response.

smashah commented 2 years ago

Unsurprisingly, others have also figured out the above.

In the client code, it can already consume the ip property from the json response to tell the client explicitly where to connect to.

All you have to do is add your explicit IP address in server.js:

        const url = schema + '://' + info.id + '.' + opt.domain || ctx.request.host;
        info.url = url;
        info.ip = '123.123.123.123'; // <<<<< add this line with your server IP address
        ctx.body = info;
        return;

https://github.com/localtunnel/server/blob/78c06f8fc43ce0eacea2aeb88f2d1d63afaf4e19/server.js#L110

then the client will override the inferred host with the explicit IP address provided by the server. IMO it should be a cli flag.

Hope that helps

smashah commented 2 years ago

Ok wow it turns out someone did think of this and somehow implemented it half way.

Step 1.

Change ./lib/server.js

add the ip flag:

    .options('ip', {
        default: undefined,
        describe: 'IP address to inform to client'
    })

&

const server = CreateServer({
    max_tcp_sockets: argv['max-sockets'],
    secure: argv.secure,
    domain: argv.domain,
    ip: argv.ip, // <<add this line
});

Step 2.

Change ./server.js in the same location as above

        const url = schema + '://' + info.id + '.' + opt.domain || ctx.request.host;
        info.url = url;
        info.ip = opt.ip; // <<<<< add this line
        ctx.body = info;
        return;

Then make sure to add your explicit ip address with the --address flag:

> lt --host https://my.tunnel.cloud --port 3000 -s dumberror --ip 123.123.123.123

That's it. Now it will work as expected. smh.

yashwanth2714 commented 11 months ago

May I know where you are hosting the localtunnel server? I am using https://render.com/ but that is not working.

image

image

yashwanth2714 commented 11 months ago

I'm experiencing a similar issue with AWS. I use EC2 for the server and Route 53 for DNS records, which are directed to the ALB with ACM for HTTPS. Sub-domains function properly when using the EC2 instance's IP address, but encounter issues when utilizing the ALB for HTTPS support. Security Group rules permit traffic from all sources. I would appreciate any assistance. I have been unable to resolve this for 10 days.