rogerweb
Phoenix application behind AWS ALB
Hi,
I’m running a Phoenix application behind a AWS ALB (Application Load Balancer), which routes requests to different applications based on the path in the requested URL.
Requests that start with /myapp are routed to my application.
The problem is that ALB doesn’t support stripping this /myapp prefix from the actual URL that goes to Phoenix (differently from nginx, haproxy, etc) and I wouldn’t like to add this prefix (a deployment configuration) to all my routes as it can only be done in compilation time (at least without having to create a router myself which I think would be overkill; I might be wrong though).
In an attempt to overcome this issue, I’ve created a simple plug that runs before everything and removes the prefix from connection’s path_info. For instance, it turns
["myapp", "assets", "app-978a7188b69b3752fe7c58e50c7e5571.js"]
into
["assets", "app-978a7188b69b3752fe7c58e50c7e5571.js"]
Also, I configure my Endpoint to use this prefix as the path so URLs generated by the application include the prefix back and are properly routed by ALB.
# runtime.exs
config :myapp, MyAppWeb.Endpoint,
url: [
host: get_env("PHX_HOST", "localhost"),
port: get_env("PHX_PORT", 4000, :int),
path: get_env("PHX_PATH", "/") # get_env is just a helper func
]
It works fine for assets and regular routes, but not for sockets and anything that uses sockets like live reloading and the dashboard. Example:
17:39:09.218 [info] GET /myapp/socket/websocket
17:39:09.280 [debug] ** (Phoenix.Router.NoRouteError) no route found for GET /socket/websocket (MyAppWeb.Router)
(myapp 1.0.0-alpha.19) lib/phoenix/router.ex:405: MyAppWeb.Router.call/2
(myapp 1.0.0-alpha.19) lib/myapp_web/endpoint.ex:1: MyAppWeb.Endpoint.plug_builder_call/2
The plug feels like a hack and it didn’t solve my problem.
Have you guys had to deal with a similar deployment? How did you manage?
Cheers!
First Post!
Exadra37
If your app deployment target for production is to be behind that aws load balancer why do you want to overcome the issue in your app? Why not keeping it simple and just add the prefix?
Doesn’t the load balancer support to invoke a lambda function?
Or if your domain is with Route53 you can try to use forwarding rules:
Most Liked
aherranz
I found a better solution using the function MyAppWeb.Endpoint.path/1 to avoid introducing a new config entry:
<meta name="live-socket-path" content={MyAppWeb.Endpoint.path "/live"} />
And let JS fail of the meta data is not defined:
let liveSocketPath = document.querySelector("meta[name='live-socket-path']").getAttribute("content");
rogerweb
Unfortunately that’s not all we need to do. To demonstrate it, one can do:
- Start fresh with
mix phx.new hello --no-ecto - Apply your first point, i.e., add the path to the Endpoint:
# runtime.exs
config :hello, HelloWeb.Endpoint,
url: [host: host, port: 443, scheme: "https", path: "/myapp"],
- Apply your second point:
// app.js
let liveSocket = new LiveSocket("/myapp/live", Socket, {params: {_csrf_token: csrfToken}})
-
Start the application with
mix phx.server -
Access http://localhost:4000/myapp
-
Observe that you got a 404 not found.
This is not a surprise as the Endpoint’s documentation tells us the url config is about how URLs are generated, it is not the base path/prefix/scope for all the routes in your app.
So this config won’t make your routes to be found, unless you manually prefix them with /myapp. As per previous posts, this was not an option because the prefix is a runtime/deployment concern, but I temporarily accepted it as a workaround just to move on. So now the page and assets (and sockets added via mix phx.gen.socket and manually prefixed) are found, great, but not the live reload frame (http://localhost:4000/myapp/phoenix/live_reload/frame). And for that, it seems there is no config to be changed.
Also, Phoenix’s dashboard generates URLs with a duplicated /myapp, like http://localhost:4000/myapp/myapp/dashboard/home
That’s why I told you
Because
Popular in Questions
Other popular topics
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









