Skip to content

Instantly share code, notes, and snippets.

@rogelio2k
Forked from cblavier/application.ex
Created April 23, 2019 03:44
Show Gist options
  • Save rogelio2k/090e8f8d7f9d9602dc0361eeed18806c to your computer and use it in GitHub Desktop.
Save rogelio2k/090e8f8d7f9d9602dc0361eeed18806c to your computer and use it in GitHub Desktop.
Cowboy 2.5 proxy, used to bind a single port (on Heroku) for umbrella Phoenix applications. It supports HTTPS and websockets properly.
defmodule MasterProxy.Application do
alias MyApp.Endpoint, as: MyAppEndpoint
alias MyApp.UserSocket, as: MyAppUserSocket
alias MyOtherApp.Endpoint, as: MyOtherAppEndpoint
alias MyOtherApp.UserSocket, as: MyOtherAppUserSocket
alias Phoenix.LiveReloader.Socket, as: LiveReloadSocket
alias Plug.Cowboy
use Application
require Logger
@port Application.get_env(:master_proxy, :port)
def start(_type, _args) do
{:ok, pid} = in_phoenix?() |> children |> run_application()
Logger.info("successfully started master_proxy on port #{to_port(@port)}")
{:ok, pid}
end
defp run_application(children) do
import Supervisor.Spec, warn: false
Supervisor.start_link(
children,
[strategy: :one_for_one, name: MasterProxy.Supervisor]
)
end
defp children(_start_cowboy = false), do: []
defp children(_start_cowboy = true) do
[
Cowboy.child_spec(
plug: nil, # since we're using manual dispatch, plug is ignored
scheme: :http,
options: [
port: to_port(@port),
dispatch: [{:_, [
websocket_handler("/my_app/live_reload/socket/websocket", MyAppEndpoint, {LiveReloadSocket, :websocket}),
websocket_handler("/my_other_app/live_reload/socket/websocket", MyOtherAppEndpoint, {LiveReloadSocket, :websocket}),
websocket_handler("/my_app/socket/websocket", MyAppEndpoint, {MyAppUserSocket, websocket: true}),
websocket_handler("/my_other_app/socket/websocket", MyOtherAppEndpoint, {MyOtherAppUserSocket, websocket: true}),
{:_, Cowboy.Handler, {MasterProxy.Plug, []}}
]}]
]
)
]
end
defp websocket_handler(path, endpoint, options) do
{path, Phoenix.Endpoint.Cowboy2Handler, {endpoint, options}}
end
# we only want the proxy to start when phoenix is started as well
# (not in iex or tests)
defp in_phoenix? do
Application.get_env(:phoenix, :serve_endpoints)
end
defp to_port(nil) do
Logger.error "Server can't start because :port in config is nil, please use a valid port number"
exit(:shutdown)
end
defp to_port(binary) when is_binary(binary), do: String.to_integer(binary)
defp to_port(integer) when is_integer(integer), do: integer
defp to_port({:system, env_var}), do: to_port(System.get_env(env_var))
end
use Mix.Config
config :master_proxy, port: 5000
import_config "#{Mix.env}.exs"
defmodule MasterProxy.Plug do
def init(options) do
options
end
def call(conn, _opts) do
if conn.request_path =~ ~r{^/other_app} do
MyOtherApp.Endpoint.call(conn, [])
else
MyApp.Endpoint.call(conn, [])
end
end
end
use Mix.Config
config :master_proxy,
port: {:system, "PORT"}
@sukidhar
Copy link

could you provide any sample repo, if this worked for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment