2

I want to host a Node.js website running on my laptop, so that it would be accessible to other people. I have tried port-forwarding on my router, but it does not work because my ISP has stopped providing public IP address to home users. Another solution i can think of, is to use Heroku to host some type of a reverse proxy, through which it would be possible to access the website.

I have seen some reverse proxies written in Go and Node.js in NPM, but they seem to use separate ports for a tunnel and public server, which Heroku does not allow. Even though Heroku allows only one port, i still think there are some ways this could still work:

  • consider first websocket user as client (website).
  • consider websocket user with a specfic url as client (website).

As it is possible that multiple users are connecting at the same time to the proxy, it might me necessary to include an id in every request/response to the client (website).

Is there some package that provides this, or in some other way, allows a client behind NAT, while still using only one port?

4
  • A reverse proxy won't work either if users/the proxy can't establish a connection to you.
    – Seth
    Oct 11, 2017 at 9:36
  • But i can connect to it, if it is hosted in Heroku. I am new to this, but if it behaves like SSH reverse tunnel, i think it could work.
    – wolfram77
    Oct 11, 2017 at 9:41
  • 1
    @Seth i was trying to make a proxy, first i tried with raw tcp locally, and it worked locally but not in Heroku, so i updated the code simulate a HTTP upgrade, and it works now! after many hours of coding and mistakes i was able to make Heroku happy. I am differentiating users from a special client with a token. I am running my server locally here arproxy.herokuapp.com and the code is here github.com/wolfram77/node-rproxy.
    – wolfram77
    Oct 15, 2017 at 19:08
  • Nice, you could consider posting it an an answer to your own question and accepting it. If you include some of your research it might be a really useful answer.
    – Seth
    Oct 16, 2017 at 6:23

1 Answer 1

2

I started, back when i was a kid i think, looking for ways to host a Public server from Local server at NPM. Searched for keywords like:

  • Reverse proxy
  • Ws tunnel
  • Reverse HTTP
  • TCP tunnel

Tried ws-tunnel:
It needed a separate port for WebSocket connection, and a separate port for hosting a Web server. Even though that way it could work, Heroku allowed only 1 port to be used, and i didnt know if any other Cloud provider would allow 2 public ports (i felt it was not possible).

Tried reverse-http:
It could act as a Reverse HTTP client. Reverse HTTP is a protocol provided by IETF. But, then i needed a Reverse HTTP server. However there still was a problem with Reverse HTTP, as it could stream only one request at a time. It was basically a HTTP connection in reverse from Public server to Local server. That meant either i would have to somehow serialize requests of multiple users to one or multiple connections (multiple Reverse HTTP connections would have to be setup between Local server and Public server).

Try using TCP packets:
Then i realized that is was possible to do this using a single connection, and a simpler non-buffered method of proxying. Reverse HTTP might need buffering if there was a new connection, and all Reverse HTTP connections were in use. Consider using simple packets, of the following format:

--------------------------------------
| Packet Size | Connection ID | Data |
--------------------------------------

I was looking for a way to do this using WebSockets, if they had some existing feature i could use, but then i saw Heroku allowed any HTTP upgrade, so i decided to go ahead with a TCP upgrade instead. I know, i made it up. Here is how the header looks like, i checked that Heroku accepts it:

GET / HTTP/1.1
Upgrade: tcp
Connection: Upgrade
Origin: XXX

Ok so now there was an idea how you could upgrade the connection between Local server and Public server using TCP, and then communicate using packets. Still however the packet format does not tell us whether the user connected, or disconnected. It only tells us what data the user sent. So i added another field to the packet:

----------------------------------------------
| Packet Size | Event | Connection ID | Data |
----------------------------------------------

One problem that was not solved yet, was distinguishing between the connection from a user and a Local server, since we are using the same port for both of them. There could be many ways to do this, but i decided to go with a specific User-Agent for the Local server.

More doubts, whether to build the public server code using Node's HTTP or using Node's TCP. This time, i was reading about chunked encoding, trailers, and decided it would just be better to use TCP. So, i would have to parse the initial request for a connection, and based on the type determined, process the request as a user or as a Local server. But i imagined there would be a performance issue as i would be parsing the HTTP headers of every connection. But if we use a rare HTTP method for quick distinction, like HEAD, we would only have to read 4 characters only. So we can now do this:

1. If first 4 characters not HEAD, process as User.
2. Parse all the HTTP headers.
3. If User-Agent is special value, process as Local server
4. Process as User.

I also added support for multiple channels to this now, which can now enable me to access as SSH server running on another machine (private ip). Moved the code and decorated the README: https://github.com/nodef/rhost.

A few interesting pages i found while searching:

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .