I’m running multiple apps on Heroku, and use a proxy app to reroute the traffic to the appropriate app;
this because Heroku allows only one port to the interwebz.
It’s working perfectly except, the phoenix channels.
I tried the following change because the web sockets connect always thows a 404.
defmodule Proxy.Plug do
require Logger
def init(options) do
options
end
def call(conn, _opts) do
cond do
conn.request_path =~ ~r{^/webapi} ->
WebApi.Endpoint.call(conn, [])
conn.scheme == :wss -> #added this line
WebApi.Endpoint.call(conn, [])
true ->
Web.Endpoint.call(conn, [])
end
end
end
How do I redirect the wss connections to the channels, are they going trough WebApi.Endpoint?
This might not be very helpful but if your proxy app is just a simple plug/cowboy combo it may be because the proxy isn’t capable of handling websocket communication properly. Websockets with only plug haven’t seemed to materialize yet (I could be wrong about that). Phoenix seems to have put in a lot of effort on top of Plug to make websockets work.
I don’t really know the answer but this is my guess.
You could try switching the proxy from a simple Plug app to Phoenix. I’ve never tried that but it could be worth a shot.
This also popped up with a simple Google search. It’s pretty recent.
I’m having a similar issue (I believe), with accessing channels through an umbrella proxy. For instance, if my umbrella is run from :4000, I can successfully access the channel app directly (eg. :4010). But if I try to connect through :4000, the router is called and returns a 404 (no route found for GET /socket/websocket). I’m still new to Elixir and Phoenix, so I’m wondering if this is simply a mistake in how I’m using Cowboy.child_spec, or maybe my endpoint conditionals. This app is currently being run on Heroku, but without the use of channels. I’d like to stick with Heroku if I can, but that will require sending all calls (http and ws) through one port.
@jos were you able to get this working locally, with all requests proxied?
I got this working after investigating the dispatch option (thanks @anthonator), which ignores the Plug provided, and allows you conditionally init endpoints based on the route (not to confused with possible conditional logic in the Plug, as that turned out to be too late).
With that little nugget of logic, I was able to handle all requests through the same port. Non-socket requests go to my proxy plug, and calls the respective endpoints.
That’s basically where I netted out as well. I didn’t break apart the dispatch as you did, but your approach looks a bit cleaner.
I’m still new to Elixir, but I’m under the impression that the Cowboy.child_spec plug isn’t called when dispatch is set, so I set the plug to nil as to not cause confusion.