I have a TCP server coded in node.js. I'd like to put it up on Heroku because it's a free service and I don't need anything more than what their free plan offers.
Now, I know very little about the inner workings of Heroku and I'm pretty new to the whole thing so I have a few questions.
Firstly, is it even possible to deploy a TCP (non-web) server? I've read that Heroku doesn't like node.js's net because it doesn't support websockets and that I should use socket.io.
So I've switched my server to socket.io. I think. Because my code more or less looks the same. I've done this as well: https://devcenter.heroku.com/articles/using-socket-io-with-node-js-on-heroku
What do I put in my Procfile instead of "web"? Also, when I tried to deploy what I currently have, the logs said that my application failed to bind to $PORT. What's $PORT? And how do I change it to the port I want?
In fact, if I don't change it, how do I know what it is so my application can connect to this server?
The free tier of Heroku does not support TCP server. Here is the reason.
To save costs and offer free services, Heroku hosts multiple free-tier apps on the same machine. These apps, one of them being yours, share the same IP address. The apps are assigned to different ports.
However, as you probably noticed, when you access your app in a browser, the port is always 80. Hence, to know which app an incoming HTTP request is looking for, the server must be looking into the HTTP headers. (For example, using HOST to find out the app name, then resolve the app name to an internal port number.)
Finally, Heroku decided to hide away the internal ports from the internet. This, along with the fact that TCP connections don't have a HOST field, makes it impossible to host a TCP server with Heroku.
To work around this, use WebSocket.
Appendix: the Research
Testing was done with a free-tier Heroku app, in March 2020.
If you make up a non-existing app name (e.g. https://hr.herokuapp.com), Heroku responds with a page saying "There's nothing here, yet."
If you first manually nslookup an existing app (e.g. https://world-of-blogs.herokuapp.com), then try to use the IP address to access the app, Heroku also responds with a page saying "There's nothing here, yet."
Heroku doesn't support a generic TCP server but you should be able to get the functionality you want with socket.io.
You need to put web in your Procfile. That's what lets Heroku bind an external connection to port 80 to the local port your web traffic will arrive you. You find that port by looking at the environment variable $PORT. More info, with examples, is here: https://devcenter.heroku.com/articles/nodejs
Related
I've been trying to deploy a repository https://github.com/evelynhathaway/triton-poll to heroku, but since I am fairly new to NodeJs, I am unable to detect the problem. But I guess it's due to the port because heroku doesn't use static ports.
Any help would be appreciated.
Thank You in advance.
I looked at the fork and you did a couple of mistakes. I don't have the time to fix, test and get it to run but I can show you how I solved it before.
All the relevant code changes can be found in this commit (different project):
https://github.com/vegeta897/d-zone/commit/63730fd7f44d2716a31fcae55990d83c84d5ffea
The project is divided into a client and server part.
You can see here, https://github.com/vegeta897/d-zone/blob/63730fd7f44d2716a31fcae55990d83c84d5ffea/script/websock.js#L16, how I combined server and client into one. This only works because the static client files are served via http/https and the server uses websocket, no http ws/wss
When you publish a server on Heroku you need to bind to their dynamic port. However when you want to access the web server you do not specify a port. The hostname is automatically translated into an ip-address + port combo. I did this here: https://github.com/vegeta897/d-zone/blob/63730fd7f44d2716a31fcae55990d83c84d5ffea/web/main.js#L44 When deployed on Heroku the socketURL does not contain a port number.
Finally you bind to the server. I did it here https://github.com/vegeta897/d-zone/blob/63730fd7f44d2716a31fcae55990d83c84d5ffea/script/websock.js#L55 and here https://github.com/vegeta897/d-zone/blob/63730fd7f44d2716a31fcae55990d83c84d5ffea/socket-config.js#L30
You also have to make sure that your clients files are built properly and served.
I have a websocket server running via NodeJS, and have deployed it to Heroku. There are two separate web applications I wrote that communicate with the websocket server. On localhost, I simply run the node server, load up the applications in a web browser, and all works fine. In Heroku, however, I can't seem to get anything to connect to the url ws://url:port - it just returns an err request timeout.
I don't want to deploy my html using Express per their example. Maybe I could, but this is a test case where some web applications get to be pretty huge.
Is my issue that I have to use wss instead of ws?
Or backing up further, is this a good use case for Heroku or is there something else I should use?
The easiest description of what I'm trying to do: Two websites hosted somewhere that isn't Heroku both communicating with a NodeJS-based websocket server hosted on Heroku.
Thanks for your help!
Alright, I feel pretty dumb because this is about as easy an answer as it gets. For anyone else trying to do the same thing, you don't need to specify the port (Heroku port is for internal use only, and the heroku url you are provided is on port 80). Simply connect using wss (e.g. wss://your-app.herokuapp.com)
I would like to create a secure internal route between two applications within the same space/organization. It should never be possible to reach the Node.js application from the outside. My Java application connects via HTTP to the Node application (running on express).
I have now tried to setup the desired configuration by creating a route called example-route.apps.internal and assigned it to the Node application. As a next step, I've opened the port (I've tried 443, 80, 8080) in the network configuration of the Java application (with the destination being the Node app). I restaged both applications.
Then, I opened a Java connection to the link http://example-route.apps.internal/test123. I've also tried to use https. The result was the same. Java refused to conncet to this URL.
Now, the following questions:
How can I properly set up this communication? Should I resolve this internal DNS somehow? Which port is the correct one if I just use the port of the env variable? How should I read this port from the other application?
How secure is the communication, if HTTP is used instead of HTTPS? (I assume HTTPS is not possible internally). Is it as safe as an HTTPS connection from the outside? Which devices are between, how far out does the connection go?
Thank you!
I think you're almost there.
Then, I opened a Java connection to the link http://example-route.apps.internal/test123. I've also tried to use https. The result was the same. Java refused to conncet to this URL.
You should use http://example-route.apps.internal:8080/test123. Your app is set to listen on $PORT, which is always 8080 in current versions of CF.
Normally you don't need to worry about this because your traffic goes in through Gorouter which translates for you (maps external port 80 -> internal 8080). With internal routes, traffic is direct so there is no transformation. That's why you need to use port 8080 in your URL.
Alternatively, you could use a service discovery mechanism like Eureka or Consul, but it's not a requirement. In this case, the service would know it's listening on 8080 and register that in the registry.
As far as HTTPS, that's tricky. Your app is only listening on 80/HTTP. You would have to change it to listen on 443/HTTPS, but then you need certs and different server configuration. It's technically possible, but it's a whole can of worms.
In some newer versions, Envoy is present and accepts HTTPS traffic into a container, can make HTTPS easier but it's still not a slam dunk (at the time of writing, at least). I expect this will get better in the future.
Should I resolve this internal DNS somehow?
Internal DNS helps with locating your other apps, not the port. Otherwise you'd need to manage IP addresses, which change often, and that would require something like Eureka or Consul.
Which port is the correct one if I just use the port of the env variable?
See above.
How should I read this port from the other application?
It's always 8080 at the moment, and has been for multiple years. It's unlikely to change, so you could probably hard code or set it in a config file safely.
How secure is the communication, if HTTP is used instead of HTTPS? (I assume HTTPS is not possible internally).
Is it as safe as an HTTPS connection from the outside? Which devices are between, how far out does the connection go?
Traffic would not be accessible externally as it wouldn't leave the Cell in some cases or worst case it goes between two Cells, but traffic would be visible internally since it's not encrypted. That means you need to have more trust on your CF provider, who would have access to internal traffic.
If it were HTTPS, only someone with the key would be able to decrypt it. You would still have to trust your provider though as they could likely get the key & use it to decrypt traffic. It would just be more work for them than if traffic is unencrypted.
Hope that helps!
Few days ago I wanted to launch my own Agario server. I assumed not to spend any money on hosting/vps etc. After a long search I found Bluemix PaaS, I put open source Agario clone Ogar (https://github.com/OgarProject/Ogar) in them and server has already started in 1523 port, but when i try to connect to this server via agario site ( connect("ws://appname.eu-gb.mybluemix.net:1523") ) I can't connect. I tried also other ways e.g. prepared agar.io link (agar.io?ip=appname.eu-gb.mybluemix.net), but nothing worked.
Has anyone met similar problem?
Inbound traffic is only on standard HTTP/HTTPS ports 80/443. Bluemix will tell your application what port to listen on with the VCAP_APP_PORT env variable. Inbound requests are then mapped to that port. So, once you bind to the VCAP_APP_PORT port, you should be able to connect to : ws://appname.eu-gb.mybluemix.net
I've used the openshift-cartridge-tcp-endpoint cartridge to try and make a TCP server which I can access from a desktop application.
I've set it up on a scaleable application and I can see the OPENSHIFT_NODEJS_PORT_TCP and OPENSHIFT_NODEJS_PROXY_PORT_TCP values when I list the environment variables using 'export' when ssh'd into my application.
The problem is, when I do 'rhc ssh APP_NAME oo-gear-registry all', no port is listed over which I can access my TCP application and when I try to access the application over the port given by the HTTP server, it does not connect. Do I have to take additional steps to make the port show up and be accessible?
It looks like that cartridge is over 2 years old, and probably doesn't work with the current version of OpenShift Online, as it only exposes port 8080 publicly and uses an HTTP/WS reverse proxy, so only http or web services connections would work. You might try logging an issue with the cartridge's creator here (https://github.com/Filirom1/openshift-cartridge-tcp-endpoint/issues) and ask them if it still works or not.