Heroku + node.js: I have a server which uses multiple ports. How can I get Heroku to allocate them?
Asked Answered
N

4

42

Umm I'll try to be more clear..

In an application server I have written in node.js, I have inner-proxy for multiple ports:

  • in my 8080 port I have my rest api.
  • in my 3000 port I have my push server and chat.

I use the npm package subdomain-router for inner-routing to the port, exposing sub-domains in the 'front-end' which proxy back to those ports.
code demonstration: (<some-app> is not the real name of the app obviously)

require('subdomain-router')
({
  host: '<some-app>.herokuapp.com',
  subdomains:
  {
    '': 8080,   // <some-app>.herokuapp.com <=> ::8080   --WORKS--
    'api': 8080,  // api.<some-app>.herokuapp.com <=> ::8080
    'chat': 3000, // chat.<some-app>.herokuapp.com <=> ::3000
    'push': 3000  // push.<some-app>.herokuapp.com <=> ::3000
  }
}).listen(process.env.PORT || 5000);

The API works great, though I cannot access it through <some-app>.herokuapp.com:8080, but only through <some-app>.herokuapp.com and let the inner subdomain-router module do it's magic.
Also, I can't access the subdomains. When trying to access api.<some-app>.herokuapp.com I get No such app error page from heroku.

TL;DR accessing <some-app>.herokuapp.com works (redirects to /v1 path for my API), but unable to access <some-app>.herokuapp.com:8080, <some-app>.herokuapp.com:3000 or chat.<some-app>.herokuapp.com.

When trying to access my API by specifying the port in the url (like this: <some-app>.herokuapp.com:8080), I get the following error in my browser (google chrome): ERR_CONNECTION_REFUSED.

My educated guess says that it might be something related to opening ports in heroku, but I have no clue on how to do it (tried googling ofc).
It doesn't explain why I cannot access the sub-domains though.

Would appreciate any light shed on this issue.
I'm new to heroku and it's getting really frustrating.

Thanks!
Amit

Nationalist answered 5/6, 2016 at 1:26 Comment(0)
N
35

Okay, after doing some research I've found out that opening ports in Heroku is disabled and not allowed.

The only way around this is to use sub-domains and then in-app to use a proxy module (like subdomain-router which I use).

BUT - Heroku don't let you create sub-domains on their domain, meaning that your-app.herokuapp.com is fixed and cannot have sub-domains.
In Heroku manuals, they demand you to have your own domain and dns provider to do such thing, by creating an A-alias (CNAME) in the dns table in your domain settings, that will refer to your app herokuapp domain, and then using the command heroku domains:add to add your domain to the allowed origin list.

You can read more here. It provides all the info you need.

Hope it helped some.

Nationalist answered 5/6, 2016 at 17:57 Comment(3)
Yeah you'll only have that one port, but you can serve your websockets through there as well as HTTP requests.Sadick
@Antoine how can both HTTP requests and TCP (websocket) messages be handled by the same port ?Succor
@Antoine I'm with vin - how does that work? I am facing the same issue but it really feels pretty annoying having to do all this working around just to be able to process some HTTP requests...Eon
E
13

I know this is an old post, but I wanted to provide an up-to-date response for reference and future use:

If you're using socket-io, binding to the same port is easy. Other websocket libs should have a similar approach (from https://github.com/socketio/socket.io#how-to-use):

In conjunction with Express Starting with 3.0, express applications have become request handler functions that you pass to http or http Server instances. You need to pass the Server to socket.io, and not the express application function. Also make sure to call .listen on the server, not the app.

const app = require('express')();
const server = require('http').createServer(app);
const io = require('socket.io')(server);
io.on('connection', () => { /* … */ });
server.listen(3000);

You'll now have http & ws traffic flowing through a single port (Heroku doesn't route http/tcp separately, if it did your websockets wouldn't work period).

I prefer this method due to environment parity & testing, i.e. no need to setup subdomains or port routing

Endothelium answered 12/3, 2019 at 13:25 Comment(0)
S
4

I also learned about this today, I learned that if you run a service on a port in Heroku, you can still access it locally. Wouldn't work for above user's concern but it did fix my issue which led me to this question.

Sadick answered 5/6, 2016 at 19:49 Comment(0)
C
0

You can create a proxy server to access any local port.

Explanation:

Heroku dockerizes your app for both security measures and to have the ability to deploy multiple apps on a single machine. This requires them to manage by themselves the exposed port (note that you cannot change the exposed port and it's only one per app).

So, if you want to expose multiple servers, you'll need to have a mapping server to proxy requests to different servers.

NextJS + NodeJS Example:

I run my NodeJS server on port 4000 (not exposed) while my NextJS app listens to Heroku's exposed port PORT=$PORT npm run --prefix ./next/ start.

NextJS allows you to rewrite requests, so I can point any request to my API to the internal port, this is my code from next.config.js

  async rewrites() {
    return {
      beforeFiles: [
        {
          source: '/health',
          destination: 'http://localhost:4000/health'
        },
        {
          source: '/v1/:path',
          destination: 'http://localhost:4000/v1/:path'
        }
      ],
      fallback: [
        {
          source: '/:path*',
          destination: 'http://localhost:4000/:path*'
        }
      ]
    };
  }

You can also do it the other way around, meaning having your API server listen to the exposed port and proxying any request to any of your internal ports.

Cootie answered 10/6, 2023 at 6:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.