2

I haven't been using Heroku in a long time so im a bit rusty. I have created a small PHP application that runs a Ratchet IOServer. It listens on port 5000. If I run heroku local and connect with telnet localhost 5000 everything seems to work. I have tried several ways of getting the PHP process to run and accepting connections.

My Procfile looks like this;

web: php bin/console bot:start

Running heroku local

Downloading forego-0.16.1 to /Users/roje/.heroku... done
forego | starting web.1 on port 8080
web.1  | It works!
web.1  | New connection! (97)
web.1  | Connection 97 sending message "sdfdfs"

When I then deploy the server to Heroku it doesn't work. When I try to telnet to the box on port 5000 I get

telnet myapplication.herokuapp.com 5000
Trying 46.137.127.234...
telnet: connect to address 46.137.127.234: Connection refused
telnet: Unable to connect to remote host

The log shows a bit more information.

2016-03-19T16:08:27.258081+00:00 heroku[web.1]: State changed from crashed to starting
2016-03-19T16:08:29.754688+00:00 heroku[web.1]: Starting process with command `php bin/console bot:start`
2016-03-19T16:08:31.659074+00:00 app[web.1]: It works!
2016-03-19T16:09:29.999903+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
2016-03-19T16:09:29.999903+00:00 heroku[web.1]: Stopping process with SIGKILL
2016-03-19T16:09:30.638659+00:00 heroku[web.1]: Process exited with status 137
2016-03-19T16:09:30.660710+00:00 heroku[web.1]: State changed from starting to crashed
2016-03-19T16:18:51.610894+00:00 heroku[web.1]: State changed from crashed to starting
2016-03-19T16:18:55.208396+00:00 heroku[web.1]: Starting process with command `php bin/console bot:start`
2016-03-19T16:18:56.648708+00:00 app[web.1]: It works!
2016-03-19T16:19:55.569256+00:00 heroku[web.1]: Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch
2016-03-19T16:19:55.569256+00:00 heroku[web.1]: Stopping process with SIGKILL
2016-03-19T16:19:56.252235+00:00 heroku[web.1]: Process exited with status 137
2016-03-19T16:19:56.264205+00:00 heroku[web.1]: State changed from starting to crashed

Any suggestions?

EDIT #1

I just read the part about Heroku assigning dynamic ports Heroku + node.js error (Web process failed to bind to $PORT within 60 seconds of launch)

I tried listening on that port instead but I still cant connect via. telnet. Though I do get some interesting logs. Maybe some of you are trying the IP address?

2016-03-19T16:38:35.577130+00:00 app[web.1]: It works!
2016-03-19T16:38:35.827466+00:00 app[web.1]: New connection! (97)
2016-03-19T16:38:35.827531+00:00 app[web.1]: Connection 97 has disconnected
2016-03-19T16:38:35.832097+00:00 app[web.1]: New connection! (107)
2016-03-19T16:38:35.832160+00:00 app[web.1]: Connection 107 has disconnected
2016-03-19T16:38:49.891455+00:00 app[web.1]: New connection! (108)
2016-03-19T16:38:49.891506+00:00 app[web.1]: Connection 108 has disconnected
2016-03-19T16:40:54.694321+00:00 app[web.1]: New connection! (109)
2016-03-19T16:40:54.694368+00:00 app[web.1]: Connection 109 has disconnected

I still get the same error though.

Trying 176.34.255.126...
telnet: connect to address 176.34.255.126: Connection refused
telnet: Unable to connect to remote host
Community
  • 1
  • 1
Ronnie Jespersen
  • 950
  • 2
  • 9
  • 22
  • I don't believe Heroku lets you connect to anything other than 80 or 443 from the outside. See http://stackoverflow.com/questions/8107748/can-a-heroku-app-use-different-multiple-ports - your port 5000 is just within the instance, but Heroku's router won't route it externally. – ceejayoz Mar 19 '16 at 16:45
  • I tried starting the IOServer on the port dynamically defined by Heroku in the environment variables. In this case the port got assigned as `40220`. Still without luck. – Ronnie Jespersen Mar 19 '16 at 16:51

2 Answers2

1

I was able to manage this using nginx as a proxy in front of the web socket.

Procfile:

web: private/bin/start_socket vendor/bin/heroku-php-nginx -C nginx_app.conf

start_socket:

php private/bin/start_socket.php &
exec "$@"

start_socket.php:

<?php
require_once(dirname(dirname(__DIR__)) . '/vendor/autoload.php');
require_once(__DIR__ . '/socket/socket.php');

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;

$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new Socket()
        )
    ),
    8085
);
$server->run();

nginx.conf:

location /wss {
    proxy_pass http://localhost:8085;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Now you can access the socket like so: ws://myapp.com/wss?mydata=test. This doesn't get around the fact that each dyno will be running it's own unique WebSocket server, but that is a completely separate question.

Maxim Mazurok
  • 3,856
  • 2
  • 22
  • 37
Floss
  • 637
  • 4
  • 16
  • This approach actually works, thanks! This answer should be accepted. I was searching for a way to set up WS as a worker alongside my main backend process, but I think that's impossible :( Any thoughts on that? – Maxim Mazurok Jul 06 '19 at 21:39
0

Based on Floss's answer... this is what worked for me for serving websockets powered by bloatless/php-websocket. Something similar will likely work for Ratchet too.

Procfile:

web: bash start vendor/bin/heroku-php-nginx -C nginx.conf

start:

php server.php &
exec "$@"

nginx.conf:

location /app {
    proxy_pass http://localhost:1112;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Sec-WebSocket-Protocol $http_sec_websocket_protocol;
    proxy_set_header Sec-WebSocket-Extensions $http_sec_websocket_extensions;
    proxy_set_header Sec-WebSocket-Key $http_sec_websocket_key;
    proxy_set_header Sec-WebSocket-Version $http_sec_websocket_version;
}

server.php will be whatever PHP file is serving your websockets application.

:1112 will be whatever port you have set your websockets application to run on.

/app will be the application name that you need to setup for Bloatless.

Note: There are other websocket headers that you may need to set too depending on which client you use. The full list of websocket headers can be found here: https://www.rfc-editor.org/rfc/rfc6455#section-11.3

Community
  • 1
  • 1
Chris Harrison
  • 5,512
  • 3
  • 28
  • 36