cblavier
Cowboy 2.5 reverse proxy with websockets
Hey folks, I’m deploying a Phoenix 1.4 umbrella app with multiple web endpoints to Heroku, so I need a single endpoint that will reverse proxy my web_apps and their websockets.
The following code is working properly to dispatch plain HTTP traffic between my apps, but Cowboy crashes when loading live_reload websockets.
I wrote this code from cowboy 1.0 examples, and I guess the way I setup dispatch has changed. But I’m struggling at reading cowboy 2.5 documentation … ![]()
My proxy application :
defmodule MyProxy.Application do
alias Plug.Cowboy
use Application
def start(_type, _args) do
import Supervisor.Spec, warn: false
port = (System.get_env("PORT") || "5000") |> String.to_integer
cowboy = Cowboy.child_spec(
scheme: :http,
plug: MyProxy.Plug,
options: [
port: port,
dispatch: [{:_, [
my_app_web_live_reload(),
my_other_app_live_reload(),
proxy()
]}]
]
)
children = [cowboy]
opts = [strategy: :one_for_one, name: MyProxy.Supervisor]
Supervisor.start_link(children, opts)
end
defp my_app_web_live_reload do
{
"/my_app/live_reload/socket/websocket",
Phoenix.Endpoint.CowboyWebSocket,
{
Phoenix.Transports.WebSocket,
{MyApp.Endpoint, Phoenix.LiveReloader.Socket, :websocket}
}
}
end
defp my_other_app_live_reload do
{
"/my_other_app/live_reload/socket/websocket",
Phoenix.Endpoint.CowboyWebSocket,
{
Phoenix.Transports.WebSocket,
{MyOtherApp.Endpoint, Phoenix.LiveReloader.Socket, :websocket}
}
}
end
defp proxy do
{:_, Cowboy.Handler, {MyProxy.Plug, []}}
end
end
and the proxy plug:
defmodule MyProxy.Plug do
def init(options) do
options
end
def call(conn, _opts) do
if conn.request_path =~ ~r{/my_app} do
MyApp.Endpoint.call(conn, [])
else
MyOtherApp.Endpoint.call(conn, [])
end
end
end
The cowboy error
[error] Ranch protocol #PID<0.1043.0> of listener MyProxy.Plug.HTTP (connection #PID<0.1042.0>, stre
am id 1) terminated
** (exit) :undef
[error] :gen_event handler :error_logger_lager_h installed in :error_logger terminating
** (CaseClauseError) no case clause matching: [MyProxy.Plug.HTTP, #PID<0.1042.0>, 1, #PID<0.1043.0>,
:undef, [{Phoenix.Endpoint.CowboyWebSocket, :init, [%{bindings: %{}, body_length: 0, cert: :undefin
ed, has_body: false, headers: %{"accept-encoding" => "gzip, deflate, br", "accept-language" => "fr-F
R,fr;q=0.9,en-US;q=0.8,en;q=0.7", "cache-control" => "no-cache", "connection" => "Upgrade" , "host"
=> "localhost:5000", "origin" => "http://localhost:5000", "pragma" => "no-cache", "sec-websocket-ext
ensions" => "permessage-deflate; client_max_window_bits", "sec-websocket-key" => "LiihXA7p3GimivqsYH
hjqg==", "sec-websocket-version" => "13", "upgrade" => "websocket", "user-agent" => "Mozilla/5.0 (Ma
cintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/
537.36"}, host: "localhost", host_info: :undefined, method: "GET", path: "/my_app/live_reload/socket
/websocket", path_info: :undefined, peer: {{127, 0, 0, 1}, 54652}, pid: #PID<0.1042.0>, port: 5000,
qs: "vsn=2.0.0", ref: MyProxy.Plug.HTTP, scheme: "http", sock: {{127, 0, 0, 1}, 5000}, streamid: 1,
version: :"HTTP/1.1"}, {Phoenix.Transports.WebSocket, {MyApp.Endpoint, Phoenix.LiveReloader.Socket,
:websocket}}], []}, {:cowboy_handler, :execute, 2, [file: 'my_app/deps/cowboy/src/cowboy_handler.erl
', line: 41]}, {:cowboy_stream_h, :execute, 3, [file: 'my_app/deps/cowboy/src/cowboy_stream_h.erl',
line: 293]}, {:cowboy_stream_h, :request_process, 3, [file: 'my_app/deps/cowboy/src/cowboy_stream_h.
erl', line: 271]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 247]}]]
Marked As Solved
cblavier
I finally figured it by myself : the Phoenix.Endpoint.CowboyWebSocket I was using is meant to be used with cowboy 1.x. For cowboy 2.x, I had to use Phoenix.Endpoint.Cowboy2Handler like this :
defp my_app_web_live_reload do
{
"/my_app/live_reload/socket/websocket",
Phoenix.Endpoint.Cowboy2Handler,,
{
MyApp.Endpoint,
{Phoenix.LiveReloader.Socket, :websocket}
}
}
end
2
Popular in Questions
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
What is the proper way to load a module from a file in to IEX?
In the python world, doing something like this pretty standard:
from ....
New
In templates/appointment/index.html.eex:
<%= for appointment <- @appointments do %>
<tr>
<td><%= appoi...
New
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
Credo is smart enough to check for (something like) this:
assert length(the_list) == 0
with this response:
Checking if an enum is empt...
New
Hello everyone,
I try to use an Javascript Event Handler in my root.html.leex file.
Therefore I created a function in the app.js file: ...
New
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar.
I p...
New
Other popular topics
Hello, how can I check the Phoenix version ?
Thanks !
New
Hi guys, i’m new in the Elixir world, and i have to say, that i love it!
i’m having some problem to understand anonymous functions with ...
New
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
New
Hello everyone,
Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










